@stylexjs/shared 0.1.0-beta.6 → 0.2.0-beta.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. package/README.md +81 -0
  2. package/lib/convert-to-className.js +13 -6
  3. package/lib/expand-shorthands.d.ts +5 -0
  4. package/lib/expand-shorthands.js +241 -101
  5. package/lib/generate-css-rule.js +10 -38
  6. package/lib/index.d.ts +14 -2
  7. package/lib/index.js.flow +5 -0
  8. package/lib/messages.js +11 -3
  9. package/lib/namespace-transforms/__tests__/preflatten.test.js +120 -0
  10. package/lib/namespace-transforms/preflatten.js +89 -0
  11. package/lib/physical-rtl/generate-ltr.js +32 -32
  12. package/lib/physical-rtl/generate-rtl.js +30 -30
  13. package/lib/preprocess-rules/PreRule.js +101 -0
  14. package/lib/preprocess-rules/application-order.js +259 -0
  15. package/lib/preprocess-rules/basic-validation.js +92 -0
  16. package/lib/preprocess-rules/expand-shorthands.js +156 -0
  17. package/lib/preprocess-rules/flatten-raw-style-obj.js +148 -0
  18. package/lib/preprocess-rules/index.js +39 -0
  19. package/lib/preprocess-rules/legacy-expand-shorthands.js +219 -0
  20. package/lib/preprocess-rules/null-out-longhand.js +310 -0
  21. package/lib/preprocess-rules/property-specificity.js +135 -0
  22. package/lib/preprocess-rules/react-native-web.js +142 -0
  23. package/lib/stylex-create.js +32 -91
  24. package/lib/stylex-defaultValue.js +397 -0
  25. package/lib/stylex-keyframes.js +23 -10
  26. package/lib/utils/Rule.js +71 -0
  27. package/lib/utils/default-options.js +34 -0
  28. package/lib/utils/genCSSRule.js +9 -8
  29. package/lib/utils/normalize-value.js +3 -0
  30. package/lib/utils/object-utils.js +24 -3
  31. package/lib/utils/property-priorities.js +116 -0
  32. package/lib/utils/split-css-value.js +47 -0
  33. package/lib/validate.js +1 -1
  34. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # @stylexjs/shared
2
+
3
+ This package contains most of the core JavaScript logic for stylex.
4
+
5
+ It exports two primary functions `create` and `keyframes`.
6
+
7
+ 1. `create` - takes a map of style rules. The return value include: a) the map with each style value replaced by a unique, reproducible, hashed className string, and b) a list of the CSS styles to be inserted into the document.
8
+ 2. `keyframes` - takes a `@keyframes` animation as JS object. Returns a hashed string and the style ot be injected.
9
+
10
+ #### ⭐️ `create`
11
+
12
+ The `stylex.create` function is implemented here and can be found within `stylex-create.js` and is the default export of a function named `styleXCreateSet(...)`.
13
+
14
+ ##### `styleXCreateSet(...)`
15
+
16
+ > The function is called `styleXCreateSet` because `stylex.create` transforms a "set" or collection of multiple style [namespaces](#namespace)
17
+
18
+ This function itself mostly just traverses over the objects to run each [namespaces](#namespace) through the `styleXCreateNamespace(...)` function. Other than that, it takes the styles to be injected from each namespace in a [Namespace Set](#namespace-set) and deduplicates them so the style isn't injected multiple times if it's used within multiple Namespaces in the same set.
19
+
20
+ ##### `styleXCreateNamespace(...)`
21
+
22
+ > This function has been kept separate in case we want to add a new function to the StyleX API in the future called `stylex.createOne` which transforms a single [namespace](#namespace) instead of a [Namespace Set](#namespace-set)
23
+
24
+ This function is responsible to transforming a [namespace](#namespace) to a [Compiled Namespace](#compiled-namespace) by hashing each key value pair and returning an object where the values have been replaced by classNames.
25
+
26
+ **Step 1**
27
+
28
+ The first step here is expanding all [shorthands](#shorthands) into their individual properties. To do this we `.flatMap` over the object entries of the Namespace and use the `expandShorthands(...)` function defined within `expand-shorthands.js`
29
+
30
+ **Step 2**
31
+
32
+ We hash each style `[key, value]` pair and generate a className and an associated CSS rule. Thie is done in the `convertToClassName(...)` function defined within [`convert-to-className.js`](#convert-to-classname-shared-package). (Explained below)
33
+
34
+ **Step 3**
35
+
36
+ Using the classNames generated in _step 2_ above, we collect all the individual style keys along with their associated classNames in the `resolvedNamespace` object.
37
+
38
+ All the generated CSS rules from _step 2_ are collected in the `injectedStyles` object.
39
+
40
+ The `[resolvedNamespace, injectedStyles]` is returned.
41
+
42
+ ##### Back to `styleXCreateSet(...)`
43
+
44
+ `styleXCreateSet(...)` takes all the `[resolvedNamespace, finalInjectedStyles]` tuples and returns a tuple of `[compiledNamespaceSet, allInjectedStyles]`
45
+
46
+ ### Back to `create` with the `@stylexjs/babel-plugin` package
47
+
48
+ The `create` function within the babel plugin package takes the `stylex.create(...)` function call and replaces it with the `compiledNamespaceSet`.
49
+
50
+ It also takes each of the `injectedStyles` and:
51
+
52
+ 1. Either injects it as a `stylex.inject` call (if in `dev` mode)
53
+ 2. Or, adds it to the array of injected styles on [`babel.state.metadata`](#babel-metadata)
54
+
55
+ #### ⭐️ `keyframes`
56
+
57
+ This is the function backing `stylex.keyframes`. It works similarly to `create` but it's more simplified since it only defines a single CSS `@keyframes` rule and returns a single string.
58
+
59
+ Here again, the source AST is converted to a JS object and passed to `stylex-keyframes.js` within the `shared` package.
60
+
61
+ There, first the shorthands are expanded and then the whole objects is hashed. The resulting hash is used as the generated `animation name` for a `@keyframes` rule.
62
+
63
+ The "name" and the CSS `@keyframes` rules are returned as a tuple.
64
+
65
+ The `stylex.keyframes` call is replaced with the final string.
66
+
67
+ The CSS `@keyframes` rule is either injected using `stylex.inject` in dev mode or set onto the `stylex` array on [`babel.state.metadata`](#babel-metadata).
68
+
69
+ #### `convert-to-className` (`shared` package)
70
+
71
+ This function is responsible for converting a single style key-value pair into a tuple of `[key, className, CSSRules]`
72
+
73
+ It does so in the following steps:
74
+
75
+ 1. Convert the camelCased keys that are used by end-users to define [Namespaces](#namespace) and convert them to the dash-separated keys used within CSS.
76
+ 2. Hash `key` + (any `pseudo` or `at-rule`) + `value` to generate a className
77
+ 3. Generate the CSS rule using the `generateCSSRule` function defined in [`generate-css-rule.js`](#generate-css-rulejs) in the `shared` package.
78
+
79
+ #### `generate-css-rule.js`
80
+
81
+ This function takes a CSS key value pair, checks if has an RTL counterpart and returns them along side a pre-configured priority based on the type of CSS rule it is.
@@ -3,11 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = convertToClassName;
6
+ exports.convertStyleToClassName = convertStyleToClassName;
7
7
  var _hash = _interopRequireDefault(require("./hash"));
8
8
  var _dashify = _interopRequireDefault(require("./utils/dashify"));
9
9
  var _transformValue = _interopRequireDefault(require("./transform-value"));
10
- var _generateCssRule = _interopRequireDefault(require("./generate-css-rule"));
10
+ var _generateCssRule = require("./generate-css-rule");
11
+ var _defaultOptions = require("./utils/default-options");
12
+ var _objectUtils = require("./utils/object-utils");
11
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
14
  /**
13
15
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -25,16 +27,21 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
25
27
  // Handles RTL-flipping
26
28
  // Hashes to get a className
27
29
  // Returns the final key, className a CSS Rule
28
- function convertToClassName(objEntry, pseudo) {
30
+ function convertStyleToClassName(objEntry, pseudos, atRules) {
29
31
  let {
30
32
  stylexSheetName = '<>',
31
33
  classNamePrefix = 'x'
32
- } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
34
+ } = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : _defaultOptions.defaultOptions;
33
35
  const [key, rawValue] = objEntry;
34
36
  const dashedKey = (0, _dashify.default)(key);
35
37
  const value = Array.isArray(rawValue) ? rawValue.map(eachValue => (0, _transformValue.default)(key, eachValue)) : (0, _transformValue.default)(key, rawValue);
36
- const stringToHash = Array.isArray(value) ? dashedKey + value.join(', ') + (pseudo ?? 'null') : dashedKey + value + (pseudo ?? 'null');
38
+ const sortedPseudos = (0, _objectUtils.arraySort)(pseudos ?? []);
39
+ const sortedAtRules = (0, _objectUtils.arraySort)(atRules ?? []);
40
+ const atRuleHashString = sortedPseudos.join('');
41
+ const pseudoHashString = sortedAtRules.join('');
42
+ const modifierHashString = atRuleHashString + pseudoHashString || 'null';
43
+ const stringToHash = Array.isArray(value) ? dashedKey + value.join(', ') + modifierHashString : dashedKey + value + modifierHashString;
37
44
  const className = classNamePrefix + (0, _hash.default)(stylexSheetName + stringToHash);
38
- const cssRules = (0, _generateCssRule.default)(className, dashedKey, value, pseudo);
45
+ const cssRules = (0, _generateCssRule.generateRule)(className, dashedKey, value, pseudos, atRules);
39
46
  return [key, className, cssRules];
40
47
  }
@@ -0,0 +1,5 @@
1
+ export const BANNED_PROPERTIES: { [key: string]: string };
2
+ export const expandedKeys: $ReadOnlyArray<string>;
3
+ export default function flatMapExpandedShorthands<T>(
4
+ objEntry: [string, T]
5
+ ): Array<[string, T]>;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = flatMapExpandedShorthands;
7
+ exports.expandedKeys = void 0;
7
8
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
8
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
10
  /**
@@ -40,143 +41,282 @@ function splitValue(str) {
40
41
  return nodes;
41
42
  }
42
43
 
43
- // TODO: to be added later.
44
- // const aliases = {
45
- // marginInlineStart: (rawValue) => [['marginStart', rawValue]],
46
- // marginInlineEnd: (rawValue) => [['marginEnd', rawValue]],
47
- // marginInline: (rawValue) => [
48
- // ['marginStart', rawValue],
49
- // ['marginEnd', rawValue],
50
- // ],
51
- // paddingInlineStart: (rawValue) => [['paddingStart', rawValue]],
52
- // paddingInlineEnd: (rawValue) => [['paddingEnd', rawValue]],
53
- // paddingInline: (rawValue) => [
54
- // ['paddingStart', rawValue],
55
- // ['paddingEnd', rawValue],
56
- // ],
57
- // // 'borderInlineStart': (rawValue) => [['borderStart', rawValue]],
58
- // // 'borderInlineEnd': (rawValue) => [['borderEnd', rawValue]],
59
- // // // This will need to change.
60
- // // 'borderInline': (rawValue) => [
61
- // // ['borderStart', rawValue],
62
- // // ['borderEnd', rawValue],
63
- // // ],
64
- // };
65
-
66
44
  /**
67
45
  * Shorthand properties:
68
46
  * - [x] all - Should be banned
69
- * - [ ] animation
70
- * - [ ] background
71
- * - [-] border
47
+ * - [x] animation
48
+ * - [x] background
49
+ * - [x] border
72
50
  * - [x] border-block-end
73
51
  * - [x] border-block-start
74
- * - [ ] border-bottom
52
+ * - [x] border-bottom
75
53
  * - [x] border-color
76
54
  * - [x] border-image
77
55
  * - [x] border-inline-end
78
56
  * - [x] border-inline-start
79
- * - [ ] border-left
57
+ * - [x] border-left
80
58
  * - [x] border-radius
81
- * - [ ] border-right
59
+ * - [x] border-right
82
60
  * - [x] border-style
83
- * - [ ] border-top
61
+ * - [x] border-top
84
62
  * - [x] border-width
85
- * - [ ] column-rule
86
- * - [ ] columns
87
- * - [ ] flex
88
- * - [ ] flex-flow
89
- * - [ ] font
90
- * - [ ] gap
91
- * - [ ] grid
92
- * - [ ] grid-area
93
- * - [ ] grid-column
94
- * - [ ] grid-row
95
- * - [ ] grid-template
96
- * - [ ] list-style
63
+ * - [x] column-rule
64
+ * - [x] columns
65
+ * - [x] container
66
+ * - [x] flex
67
+ * - [x] flex-flow
68
+ * - [x] font
69
+ * - [x] gap
70
+ * - [x] grid
71
+ * - [x] grid-area
72
+ * - [x] grid-column
73
+ * - [x] grid-row
74
+ * - [x] grid-template
75
+ * - [x] inset
76
+ * - [x] inset-block
77
+ * - [x] inset-inline
78
+ * - [x] list-style
97
79
  * - [x] margin
98
- * - [ ] mask
99
- * - [ ] offset
100
- * - [ ] outline
80
+ * - [x] mask
81
+ * - [x] offset
82
+ * - [x] outline
101
83
  * - [x] overflow
102
84
  * - [x] padding
103
- * - [ ] place-content
104
- * - [ ] place-items
105
- * - [ ] place-self
106
- * - [ ] scroll-margin
107
- * - [ ] scroll-padding
108
- * - [ ] text-decoration
109
- * - [ ] text-emphasis
110
- * - [ ] transition
85
+ * - [x] place-content
86
+ * - [x] place-items
87
+ * - [x] place-self
88
+ * - [x] scroll-margin
89
+ * - [x] scroll-padding
90
+ * - [x] text-decoration
91
+ * - [x] text-emphasis
92
+ * - [x] transition
111
93
  */
112
94
 
113
- const expansions = {
114
- // ...aliases,
95
+ const shorthands = {
96
+ all: _ => {
97
+ throw new Error('all is not supported');
98
+ },
99
+ animation: value => [['animation', value], ['animationName', null], ['animationDuration', null], ['animationTimingFunction', null], ['animationDelay', null], ['animationIterationCount', null], ['animationDirection', null], ['animationFillMode', null], ['animationPlayState', null]],
100
+ background: value => [['background', value], ['backgroundAttachment', null], ['backgroundClip', null], ['backgroundColor', null], ['backgroundImage', null], ['backgroundOrigin', null], ['backgroundPosition', null], ['backgroundRepeat', null], ['backgroundSize', null]],
101
+ // These will be removed later, matching the properties with React Native.
102
+ // For now, we're compiling them to the React Native properties.
103
+ // @Deprecated
115
104
  border: rawValue => {
116
- return [['borderTop', rawValue], ['borderEnd', rawValue], ['borderBottom', rawValue], ['borderStart', rawValue]];
105
+ if (typeof rawValue === 'number') {
106
+ return shorthands.borderWidth(rawValue);
107
+ }
108
+ const [width, style, color] = splitValue(rawValue);
109
+ return [...shorthands.borderWidth(width), ...shorthands.borderStyle(style), ...shorthands.borderColor(color)];
117
110
  },
118
- /*
119
- // Add this later, as this will be a breaking change
120
- border: (rawValue: string) => {
111
+ // @Deprecated
112
+ borderInline: rawValue => {
121
113
  if (typeof rawValue === 'number') {
122
- return expansions.borderWidth(rawValue);
114
+ return [['borderInlineWidth', rawValue], ['borderInlineStartWidth', null], ['borderInlineEndWidth', null]];
123
115
  }
124
116
  const [width, style, color] = splitValue(rawValue);
125
- return [
126
- ...expansions.borderWidth(width),
127
- ...expansions.borderStyle(style),
128
- ...expansions.borderColor(color),
129
- ];
130
- }
131
- */
132
- borderColor: rawValue => {
133
- const [top, right = top, bottom = top, left = right] = splitValue(rawValue);
134
- return [['borderTopColor', top], ['borderEndColor', right], ['borderBottomColor', bottom], ['borderStartColor', left]];
117
+ return [...shorthands.borderInlineWidth(width), ...shorthands.borderInlineStyle(style), ...shorthands.borderInlineColor(color)];
135
118
  },
136
- borderHorizontal: rawValue => {
137
- return [['borderStart', rawValue], ['borderEnd', rawValue]];
119
+ // @Deprecated
120
+ borderBlock: rawValue => {
121
+ if (typeof rawValue === 'number') {
122
+ return [['borderBlockWidth', rawValue], ['borderTopWidth', null], ['borderBottomWidth', null]];
123
+ }
124
+ const [width, style, color] = splitValue(rawValue);
125
+ return [...shorthands.borderBlockWidth(width), ...shorthands.borderBlockStyle(style), ...shorthands.borderBlockColor(color)];
138
126
  },
139
- borderStyle: rawValue => {
140
- const [top, right = top, bottom = top, left = right] = splitValue(rawValue);
141
- return [['borderTopStyle', top], ['borderEndStyle', right], ['borderBottomStyle', bottom], ['borderStartStyle', left]];
127
+ // @Deprecated
128
+ borderTop: rawValue => {
129
+ if (typeof rawValue === 'number') {
130
+ return [['borderTopWidth', rawValue]];
131
+ }
132
+ const [width, style, color] = splitValue(rawValue);
133
+ return [['borderTopWidth', width], ['borderTopStyle', style], ['borderTopColor', color]];
142
134
  },
143
- borderVertical: rawValue => {
144
- return [['borderTop', rawValue], ['borderBottom', rawValue]];
135
+ // @Deprecated
136
+ borderInlineEnd: rawValue => {
137
+ if (typeof rawValue === 'number') {
138
+ return [['borderInlineEndWidth', rawValue]];
139
+ }
140
+ const [width, style, color] = splitValue(rawValue);
141
+ return [['borderInlineEndWidth', width], ['borderInlineEndStyle', style], ['borderInlineEndColor', color]];
145
142
  },
146
- borderWidth: rawValue => {
147
- const [top, right = top, bottom = top, left = right] = typeof rawValue === 'number' ? [rawValue] : splitValue(rawValue);
148
- return [['borderTopWidth', top], ['borderEndWidth', right], ['borderBottomWidth', bottom], ['borderStartWidth', left]];
143
+ // @Deprecated
144
+ borderRight: rawValue => {
145
+ throw new Error(['`borderRight` is not supported.', 'You could use `borderRightWidth`, `borderRightStyle` and `borderRightColor`,', 'but it is preferable to use `borderInlineEndWidth`, `borderInlineEndStyle` and `borderInlineEndColor`.'].join(' '));
149
146
  },
150
- borderRadius: rawValue => {
151
- const [top, right = top, bottom = top, left = right] = typeof rawValue === 'string' ? splitValue(rawValue) : typeof rawValue === 'number' ? [rawValue] : rawValue; // remove
152
-
153
- return [['borderTopStartRadius', top], ['borderTopEndRadius', right], ['borderBottomEndRadius', bottom], ['borderBottomStartRadius', left]];
147
+ // @Deprecated
148
+ borderBottom: rawValue => {
149
+ if (typeof rawValue === 'number') {
150
+ return [['borderBottomWidth', rawValue]];
151
+ }
152
+ const [width, style, color] = splitValue(rawValue);
153
+ return [['borderBottomWidth', width], ['borderBottomStyle', style], ['borderBottomColor', color]];
154
154
  },
155
- margin: rawValue => {
156
- const [top, right = top, bottom = top, left = right] = typeof rawValue === 'number' ? [rawValue] : splitValue(rawValue);
157
- return [['marginTop', top], ['marginEnd', right], ['marginBottom', bottom], ['marginStart', left]];
155
+ // @Deprecated
156
+ borderInlineStart: rawValue => {
157
+ if (typeof rawValue === 'number') {
158
+ return [['borderInlineStartWidth', rawValue]];
159
+ }
160
+ const [width, style, color] = splitValue(rawValue);
161
+ return [['borderInlineStartWidth', width], ['borderInlineStartStyle', style], ['borderInlineStartColor', color]];
158
162
  },
159
- marginHorizontal: rawValue => {
160
- return [['marginStart', rawValue], ['marginEnd', rawValue]];
163
+ // @Deprecated
164
+ borderLeft: rawValue => {
165
+ throw new Error(['`borderLeft` is not supported.', 'You could use `borderLeftWidth`, `borderLeftStyle` and `borderLeftColor`,', 'but it is preferable to use `borderInlineStartWidth`, `borderInlineStartStyle` and `borderInlineStartColor`.'].join(' '));
161
166
  },
162
- marginVertical: rawValue => {
163
- return [['marginTop', rawValue], ['marginBottom', rawValue]];
167
+ borderInlineWidth: rawValue => [['borderInlineWidth', rawValue], ['borderInlineStartWidth', null], ['borderLeftWidth', null], ['borderInlineEndWidth', null], ['borderRightWidth', null]],
168
+ borderInlineStyle: rawValue => [['borderInlineStyle', rawValue], ['borderInlineStartStyle', null], ['borderLeftStyle', null], ['borderInlineEndStyle', null], ['borderRightStyle', null]],
169
+ borderInlineColor: rawValue => [['borderInlineColor', rawValue], ['borderInlineStartColor', null], ['borderLeftColor', null], ['borderInlineEndColor', null], ['borderRightColor', null]],
170
+ borderBlockWidth: rawValue => [['borderBlockWidth', rawValue], ['borderTopWidth', null], ['borderBottomWidth', null]],
171
+ borderBlockStyle: rawValue => [['borderBlockStyle', rawValue], ['borderTopStyle', null], ['borderBottomStyle', null]],
172
+ borderBlockColor: rawValue => [['borderBlockColor', rawValue], ['borderTopColor', null], ['borderBottomColor', null]],
173
+ borderColor: value => [['borderColor', value], ['borderTopColor', null], ['borderInlineEndColor', null], ['borderRightColor', null], ['borderBottomColor', null], ['borderInlineStartColor', null], ['borderLeftColor', null]],
174
+ borderStyle: value => [['borderStyle', value], ['borderTopStyle', null], ['borderInlineEndStyle', null], ['borderRightStyle', null], ['borderBottomStyle', null], ['borderInlineStartStyle', null], ['borderLeftStyle', null]],
175
+ borderWidth: value => [['borderWidth', value], ['borderTopWidth', null], ['borderInlineEndWidth', null], ['borderRightWidth', null], ['borderBottomWidth', null], ['borderInlineStartWidth', null], ['borderLeftWidth', null]],
176
+ borderRadius: value => {
177
+ const values = typeof value === 'number' ? [value] : splitValue(value);
178
+ if (values.length === 1) {
179
+ return [['borderRadius', value],
180
+ // // logical constituents
181
+ ['borderStartStartRadius', null], ['borderStartEndRadius', null], ['borderEndStartRadius', null], ['borderEndEndRadius', null],
182
+ // physical constituents
183
+ ['borderTopLeftRadius', null], ['borderTopRightRadius', null], ['borderBottomLeftRadius', null], ['borderBottomRightRadius', null]];
184
+ }
185
+
186
+ // @Deprecated
187
+ const [startStart, startEnd = startStart, endEnd = startStart, endStart = startEnd] = values;
188
+ return [
189
+ // split into logical consituents
190
+ ['borderStartStartRadius', startStart], ['borderStartEndRadius', startEnd], ['borderEndEndRadius', endEnd], ['borderEndStartRadius', endStart],
191
+ // unset physical consituents
192
+ ['borderTopLeftRadius', null], ['borderTopRightRadius', null], ['borderBottomLeftRadius', null], ['borderBottomRightRadius', null]];
164
193
  },
165
- overflow: rawValue => {
166
- const [x, y = x] = splitValue(rawValue);
167
- return [['overflowX', x], ['overflowY', y]];
194
+ columnRule: value => [['columnRule', value], ['columnRuleWidth', null], ['columnRuleStyle', null], ['columnRuleColor', null]],
195
+ columns: value => [['columns', value], ['columnCount', null], ['columnWidth', null]],
196
+ container: value => [['container', value], ['containerName', null], ['containerType', null]],
197
+ flex: value => [['flex', value], ['flexGrow', null], ['flexShrink', null], ['flexBasis', null]],
198
+ flexFlow: value => [['flexFlow', value], ['flexDirection', null], ['flexWrap', null]],
199
+ // @Deprecated ?
200
+ font: value => [['font', value], ['fontFamily', null], ['fontSize', null], ['fontStretch', null], ['fontStyle', null], ['fontVariant', null], ['fontWeight', null], ['lineHeight', null]],
201
+ gap: value => [['gap', value], ['rowGap', null], ['columnGap', null]],
202
+ grid: value => [['grid', value], ['gridTemplate', null], ['gridTemplateAreas', null], ['gridTemplateColumns', null], ['gridTemplateRows', null], ['gridAutoRows', null], ['gridAutoColumns', null], ['gridAutoFlow', null]
203
+
204
+ // This is for grid items only
205
+ // Not a constituent of `grid`
206
+ // ['gridRow', null],
207
+ // ['gridRowStart', null],
208
+ // ['gridRowEnd', null],
209
+ // ['gridColumn', null],
210
+ // ['gridColumnStart', null],
211
+ // ['gridColumnEnd', null],
212
+ // ['gridArea', null],
213
+ ],
214
+
215
+ gridArea: value => [['gridArea', value], ['gridRow', null], ['gridRowStart', null], ['gridRowEnd', null], ['gridColumn', null], ['gridColumnStart', null], ['gridColumnEnd', null]],
216
+ gridRow: value => [['gridRow', value], ['gridRowStart', null], ['gridRowEnd', null]],
217
+ gridColumn: value => [['gridColumn', value], ['gridColumnStart', null], ['gridColumnEnd', null]],
218
+ gridTemplate: value => [['gridTemplate', value], ['gridTemplateAreas', null], ['gridTemplateColumns', null], ['gridTemplateRows', null]],
219
+ inset: value => [['inset', value], ['insetInline', null], ['insetBlock', null], ['insetInlineStart', null], ['insetInlineEnd', null], ['top', null], ['right', null], ['bottom', null], ['left', null]],
220
+ insetInline: value => [['insetInline', value], ['insetInlineStart', null], ['insetInlineEnd', null], ['left', null], ['right', null]],
221
+ insetBlock: value => [['insetBlock', value], ['top', null], ['bottom', null]],
222
+ listStyle: value => [['listStyle', value], ['listStyleImage', null], ['listStylePosition', null], ['listStyleType', null]],
223
+ margin: value => {
224
+ const values = typeof value === 'number' ? [value] : splitValue(value);
225
+ if (values.length === 1) {
226
+ return [['margin', values[0]], ['marginInlineStart', null], ['marginLeft', null], ['marginInlineEnd', null], ['marginRight', null], ['marginTop', null], ['marginBottom', null]];
227
+ }
228
+ // @Deprecated
229
+ const [top, right = top, bottom = top, left = right] = values;
230
+ return [['marginTop', top], ['marginInlineEnd', right], ['marginBottom', bottom], ['marginInlineStart', left], ['marginLeft', null], ['marginRight', null]];
168
231
  },
232
+ marginInline: value => [['marginInline', value], ['marginInlineStart', null], ['marginLeft', null], ['marginInlineEnd', null], ['marginRight', null]],
233
+ marginBlock: value => [['marginBlock', value], ['marginTop', null], ['marginBottom', null]],
234
+ mask: value => [['mask', value], ['maskClip', null], ['maskComposite', null], ['maskImage', null], ['maskMode', null], ['maskOrigin', null], ['maskPosition', null], ['maskRepeat', null], ['maskSize', null]],
235
+ offset: value => [['offset', value], ['offsetAnchor', null], ['offsetDistance', null], ['offsetPath', null], ['offsetPosition', null], ['offsetRotate', null]],
236
+ outline: value => [['outline', value], ['outlineColor', null], ['outlineStyle', null], ['outlineWidth', null]],
237
+ overflow: value => [['overflow', value], ['overflowX', null], ['overflowY', null]],
169
238
  padding: rawValue => {
170
- const [top, right = top, bottom = top, left = right] = typeof rawValue === 'number' ? [rawValue] : splitValue(rawValue);
239
+ const values = typeof rawValue === 'number' ? [rawValue] : splitValue(rawValue);
240
+ if (values.length === 1) {
241
+ return [['padding', values[0]], ['paddingStart', null], ['paddingLeft', null], ['paddingEnd', null], ['paddingRight', null], ['paddingTop', null], ['paddingBottom', null]];
242
+ }
243
+ // @Deprecated
244
+ const [top, right = top, bottom = top, left = right] = values;
171
245
  return [['paddingTop', top], ['paddingEnd', right], ['paddingBottom', bottom], ['paddingStart', left]];
172
246
  },
173
- paddingHorizontal: rawValue => {
174
- return [['paddingStart', rawValue], ['paddingEnd', rawValue]];
175
- },
176
- paddingVertical: rawValue => {
177
- return [['paddingTop', rawValue], ['paddingBottom', rawValue]];
178
- }
247
+ paddingInline: rawValue => [['paddingInline', rawValue], ['paddingStart', null], ['paddingLeft', null], ['paddingEnd', null], ['paddingRight', null]],
248
+ paddingBlock: rawValue => [['paddingBlock', rawValue], ['paddingTop', null], ['paddingBottom', null]],
249
+ placeContent: value => [['placeContent', value], ['alignContent', null], ['justifyContent', null]],
250
+ placeItems: value => [['placeItems', value], ['alignItems', null], ['justifyItems', null]],
251
+ placeSelf: value => [['placeSelf', value], ['alignSelf', null], ['justifySelf', null]],
252
+ scrollMargin: value => [['scrollMargin', value], ['scrollMarginBottom', null], ['scrollMarginLeft', null], ['scrollMarginStart', null], ['scrollMarginRight', null], ['scrollMarginEnd', null], ['scrollMarginTop', null]],
253
+ scrollPadding: value => [['scrollPadding', value], ['scrollPaddingBottom', null], ['scrollPaddingLeft', null], ['scrollPaddingStart', null], ['scrollPaddingRight', null], ['scrollPaddingEnd', null], ['scrollPaddingTop', null]],
254
+ scrollTimeline: value => [['scrollTimeline', value], ['scrollTimelineName', null], ['scrollTimelineAxis', null]],
255
+ textDecoration: value => [['textDecoration', value], ['textDecorationColor', null], ['textDecorationLine', null], ['textDecorationStyle', null], ['textDecorationThickness', null]],
256
+ textEmphasis: value => [['textEmphasis', value], ['textEmphasisColor', null], ['textEmphasisStyle', null]],
257
+ transition: value => [['transition', value], ['transitionDelay', null], ['transitionDuration', null], ['transitionProperty', null], ['transitionTimingFunction', null]]
179
258
  };
259
+ const aliases = {
260
+ // @Deprecated
261
+ borderHorizontal: shorthands.borderInline,
262
+ // @Deprecated
263
+ borderVertical: shorthands.borderBlock,
264
+ // @Deprecated
265
+ borderBlockStart: shorthands.borderTop,
266
+ // @Deprecated
267
+ borderEnd: shorthands.borderInlineEnd,
268
+ // @Deprecated
269
+ borderBlockEnd: shorthands.borderBottom,
270
+ // @Deprecated
271
+ borderStart: shorthands.borderInlineStart,
272
+ borderHorizontalWidth: shorthands.borderInlineWidth,
273
+ borderHorizontalStyle: shorthands.borderInlineStyle,
274
+ borderHorizontalColor: shorthands.borderInlineColor,
275
+ borderVerticalWidth: shorthands.borderBlockWidth,
276
+ borderVerticalStyle: shorthands.borderBlockStyle,
277
+ borderVerticalColor: shorthands.borderBlockColor,
278
+ borderBlockStartColor: value => [['borderTopColor', value]],
279
+ borderBlockEndColor: value => [['borderBottomColor', value]],
280
+ borderStartColor: value => [['borderInlineStartColor', value]],
281
+ borderEndColor: value => [['borderInlineEndColor', value]],
282
+ borderBlockStartStyle: value => [['borderTopStyle', value]],
283
+ borderBlockEndStyle: value => [['borderBottomStyle', value]],
284
+ borderStartStyle: value => [['borderInlineStartStyle', value]],
285
+ borderEndStyle: value => [['borderInlineEndStyle', value]],
286
+ borderBlockStartWidth: value => [['borderTopWidth', value]],
287
+ borderBlockEndWidth: value => [['borderBottomWidth', value]],
288
+ borderStartWidth: value => [['borderInlineStartWidth', value]],
289
+ borderEndWidth: value => [['borderInlineEndWidth', value]],
290
+ borderTopStartRadius: value => [['borderStartStartRadius', value]],
291
+ borderTopEndRadius: value => [['borderStartEndRadius', value]],
292
+ borderBottomStartRadius: value => [['borderEndStartRadius', value]],
293
+ borderBottomEndRadius: value => [['borderEndEndRadius', value]],
294
+ marginBlockStart: value => [['marginTop', value]],
295
+ marginBlockEnd: value => [['marginBottom', value]],
296
+ marginStart: value => [['marginInlineStart', value]],
297
+ marginEnd: value => [['marginInlineEnd', value]],
298
+ marginHorizontal: shorthands.marginInline,
299
+ marginVertical: shorthands.marginBlock,
300
+ paddingBlockStart: rawValue => [['paddingTop', rawValue]],
301
+ paddingBlockEnd: rawValue => [['paddingBottom', rawValue]],
302
+ paddingStart: rawValue => [['paddingInlinStart', rawValue]],
303
+ paddingEnd: rawValue => [['paddingInlineEnd', rawValue]],
304
+ paddingHorizontal: shorthands.paddingInline,
305
+ paddingVertical: shorthands.paddingBlock,
306
+ insetBlockStart: value => [['top', value]],
307
+ insetBlockEnd: value => [['bottom', value]],
308
+ start: value => [['insetInlineStart', value]],
309
+ end: value => [['insetInlineEnd', value]]
310
+ };
311
+ const expansions = {
312
+ ...shorthands,
313
+ ...aliases
314
+ };
315
+
316
+ // TODO: It should be possible to remove this as we should no longer have
317
+ // to disallow shorthand properties with object values.
318
+ const expandedKeys = Object.keys(expansions);
319
+ exports.expandedKeys = expandedKeys;
180
320
  function flatMapExpandedShorthands(objEntry) {
181
321
  const [key, value] = objEntry;
182
322
  const expansion = expansions[key];
@@ -3,10 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = generateCSSRule;
6
+ exports.generateRule = generateRule;
7
7
  var _generateLtr = _interopRequireDefault(require("./physical-rtl/generate-ltr"));
8
8
  var _generateRtl = _interopRequireDefault(require("./physical-rtl/generate-rtl"));
9
- var _genCSSRule = _interopRequireDefault(require("./utils/genCSSRule"));
9
+ var _genCSSRule = require("./utils/genCSSRule");
10
+ var _propertyPriorities = _interopRequireDefault(require("./utils/property-priorities"));
10
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12
  /**
12
13
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -17,48 +18,19 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
17
18
  *
18
19
  */
19
20
 
20
- function generateCSSRule(className, key, value, pseudo) {
21
+ function generateRule(className, key,
22
+ // pre-dashed
23
+ value, pseudos, atRules) {
21
24
  const pairs = Array.isArray(value) ? value.map(eachValue => [key, eachValue]) : [[key, value]];
22
25
  const ltrPairs = pairs.map(_generateLtr.default);
23
26
  const ltrDecls = ltrPairs.map(pair => pair.join(':')).join(';');
24
27
  const rtlDecls = pairs.map(_generateRtl.default).filter(Boolean).map(pair => pair.join(':')).join(';');
25
- const ltrRule = (0, _genCSSRule.default)(className, ltrDecls, pseudo);
26
- const rtlRule = !rtlDecls ? null : (0, _genCSSRule.default)(className, rtlDecls, pseudo);
27
- let priority = 1;
28
- if (pseudo != null) {
29
- if (pseudo[0] === '@') {
30
- priority = 2;
31
- } else if (pseudo[0] === ':') {
32
- priority = pseudoPriorities[pseudo] ?? 2;
33
- if (pseudo.startsWith(':nth-child')) {
34
- priority = 6;
35
- }
36
- if (pseudo.startsWith(':nth-of-type')) {
37
- priority = 7;
38
- }
39
- }
40
- }
41
- if (key.toLowerCase().includes('left') || key.toLowerCase().includes('right')) {
42
- // Bump priority for physical left/right values.
43
- priority += 0.1;
44
- }
28
+ const ltrRule = (0, _genCSSRule.genCSSRule)(className, ltrDecls, pseudos, atRules);
29
+ const rtlRule = !rtlDecls ? null : (0, _genCSSRule.genCSSRule)(className, rtlDecls, pseudos, atRules);
30
+ const priority = (0, _propertyPriorities.default)(key) + Math.max(...pseudos.map(_propertyPriorities.default), ...atRules.map(_propertyPriorities.default), 0);
45
31
  return {
46
32
  priority,
47
33
  ltr: ltrRule,
48
34
  rtl: rtlRule
49
35
  };
50
- }
51
- const pseudoPriorities = {
52
- // Might become unsupported:
53
- ':first-child': 3,
54
- ':last-child': 4,
55
- ':only-child': 5,
56
- ':nth-child': 6,
57
- ':nth-of-type': 7,
58
- ':hover': 8,
59
- ':focus': 9,
60
- ':active': 10,
61
- ':disabled': 11,
62
- '::placeholder': 12,
63
- '::thumb': 13
64
- };
36
+ }
package/lib/index.d.ts CHANGED
@@ -25,10 +25,12 @@ export type InjectableStyle = {
25
25
  export type StyleRule = readonly [string, string, InjectableStyle];
26
26
 
27
27
  export type CompiledStyles = {
28
- readonly [key: string]: string | { readonly [key: string]: string };
28
+ readonly [key: string]: string | null;
29
+ readonly $$css: true;
29
30
  };
30
31
  export type MutableCompiledStyles = {
31
- [key: string]: string | { [key: string]: string };
32
+ [key: string]: string | null;
33
+ $$css: true;
32
34
  };
33
35
 
34
36
  export type CompiledNamespaces = { readonly [key: string]: CompiledStyles };
@@ -62,6 +64,13 @@ export type StyleXOptions = {
62
64
  stylexSheetName?: string | undefined;
63
65
  classNamePrefix: string;
64
66
  definedStylexCSSVariables?: { [key: string]: any };
67
+ styleResolution:
68
+ | 'application-order' // The last style applied wins.
69
+ // More specific styles will win over less specific styles. (margin-top wins over margin)
70
+ | 'property-specificity'
71
+ // Legacy behavior, that expands shorthand properties into their longhand counterparts at compile-time.
72
+ // This is not recommended, and will be removed in a future version.
73
+ | 'legacy-expand-shorthands';
65
74
  [key: string]: any;
66
75
  };
67
76
 
@@ -87,4 +96,7 @@ export const messages: {
87
96
  LOCAL_ONLY: string;
88
97
  UNEXPECTED_ARGUMENT: string;
89
98
  EXPECTED_FUNCTION_CALL: string;
99
+ INVALID_PSEUDO_OR_AT_RULE: string;
100
+ ONLY_TOP_LEVEL_INLCUDES: string;
101
+ DUPLICATE_CONDITIONAL: string;
90
102
  };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Flowtype definitions for index.js
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.21.0
5
+ */