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

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 (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
+ */