@compiled/react 0.18.2 → 0.18.4

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.
@@ -1,22 +1,21 @@
1
1
  /**
2
- * Joins classes together and ensures atomic declarations of a single group exist.
3
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
4
- * where both `group` and `value` are hashes **four characters long**.
5
- * Class names can be of any length,
6
- * this function can take both atomic declarations and class names.
2
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
3
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
7
4
  *
8
- * Input:
9
- *
10
- * ```
11
- * ax(['_aaaabbbb', '_aaaacccc'])
5
+ * ```ts
6
+ * ax(['_aaaabbbb', '_aaaacccc']);
7
+ * // output
8
+ * '_aaaacccc'
12
9
  * ```
13
10
  *
14
- * Output:
11
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
15
12
  *
16
- * ```
17
- * '_aaaacccc'
18
- * ```
13
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
19
14
  *
20
- * @param classes
15
+ * ```ts
16
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
17
+ * // output
18
+ * '_aaaacccc border-red'
19
+ * ```
21
20
  */
22
21
  export default function ax(classNames: (string | undefined | null | false)[]): string | undefined;
@@ -1,53 +1,86 @@
1
- const UNDERSCORE_UNICODE = 95;
2
1
  /**
3
2
  * This length includes the underscore,
4
3
  * e.g. `"_1s4A"` would be a valid atomic group hash.
5
4
  */
6
5
  const ATOMIC_GROUP_LENGTH = 5;
7
6
  /**
8
- * Joins classes together and ensures atomic declarations of a single group exist.
9
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
10
- * where both `group` and `value` are hashes **four characters long**.
11
- * Class names can be of any length,
12
- * this function can take both atomic declarations and class names.
7
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
8
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
13
9
  *
14
- * Input:
15
- *
16
- * ```
17
- * ax(['_aaaabbbb', '_aaaacccc'])
10
+ * ```ts
11
+ * ax(['_aaaabbbb', '_aaaacccc']);
12
+ * // output
13
+ * '_aaaacccc'
18
14
  * ```
19
15
  *
20
- * Output:
16
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
21
17
  *
22
- * ```
23
- * '_aaaacccc'
24
- * ```
18
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
25
19
  *
26
- * @param classes
20
+ * ```ts
21
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
22
+ * // output
23
+ * '_aaaacccc border-red'
24
+ * ```
27
25
  */
28
26
  export default function ax(classNames) {
29
- if (classNames.length <= 1 && (!classNames[0] || classNames[0].indexOf(' ') === -1)) {
30
- // short circuit if there's no custom class names.
31
- return classNames[0] || undefined;
27
+ // Shortcut: nothing to do
28
+ if (!classNames.length) {
29
+ return;
32
30
  }
33
- const atomicGroups = {};
34
- for (let i = 0; i < classNames.length; i++) {
35
- const cls = classNames[i];
36
- if (!cls) {
31
+ // Shortcut: don't need to do anything if we only have a single classname
32
+ if (classNames.length === 1 &&
33
+ classNames[0] &&
34
+ // checking to see if `classNames[0]` is a string that contains other classnames
35
+ !classNames[0].includes(' ')) {
36
+ return classNames[0];
37
+ }
38
+ // Using an object rather than a `Map` as it performed better in our benchmarks.
39
+ // Would be happy to move to `Map` if it proved to be better under real conditions.
40
+ const map = {};
41
+ // Note: using loops to minimize iterations over the collection
42
+ for (const value of classNames) {
43
+ // Exclude all falsy values, which leaves us with populated strings
44
+ if (!value) {
37
45
  continue;
38
46
  }
39
- const groups = cls.split(' ');
40
- for (let x = 0; x < groups.length; x++) {
41
- const atomic = groups[x];
42
- const atomicGroupName = atomic.slice(0, atomic.charCodeAt(0) === UNDERSCORE_UNICODE ? ATOMIC_GROUP_LENGTH : undefined);
43
- atomicGroups[atomicGroupName] = atomic;
47
+ // a `value` can contain multiple classnames
48
+ const list = value.split(' ');
49
+ for (const className of list) {
50
+ /**
51
+ * For atomic style classnames: the `key` is the `group`
52
+ *
53
+ * - Later atomic classnames with the same `group` will override earlier ones
54
+ * (which is what we want).
55
+ * - Assumes atomic classnames are the only things that start with `_`
56
+ * - Could use a regex to ensure that atomic classnames are structured how we expect,
57
+ * but did not add that for now as it did slow things down a bit.
58
+ *
59
+ * For other classnames: the `key` is the whole classname
60
+ * - Okay to remove duplicates as doing so does not impact specificity
61
+ *
62
+ * */
63
+ const key = className.startsWith('_') ? className.slice(0, ATOMIC_GROUP_LENGTH) : className;
64
+ map[key] = className;
44
65
  }
45
66
  }
46
- let str = '';
47
- for (const key in atomicGroups) {
48
- const value = atomicGroups[key];
49
- str += value + ' ';
67
+ /**
68
+ * We are converting the `map` into a string.
69
+ *
70
+ * The simple way to do this would be `Object.values(map).join(' ')`.
71
+ * However, the approach below performs 10%-20% better in benchmarks.
72
+ *
73
+ * For `ax()` it feels right to squeeze as much runtime performance out as we can.
74
+ */
75
+ let result = '';
76
+ for (const key in map) {
77
+ result += map[key] + ' ';
78
+ }
79
+ // If we have an empty string, then our `map` was empty.
80
+ if (!result) {
81
+ return;
50
82
  }
51
- return str.slice(0, -1);
83
+ // remove last " " from the result (we added " " at the end of every value)
84
+ return result.trimEnd();
52
85
  }
53
86
  //# sourceMappingURL=ax.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ax.js","sourceRoot":"","sources":["../../../src/runtime/ax.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,UAAU,EAAE,CAAC,UAAiD;IAC1E,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACnF,kDAAkD;QAClD,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;KACnC;IAED,MAAM,YAAY,GAA2B,EAAE,CAAC;IAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE;YACR,SAAS;SACV;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAClC,CAAC,EACD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAC9E,CAAC;YACF,YAAY,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;SACxC;KACF;IAED,IAAI,GAAG,GAAG,EAAE,CAAC;IAEb,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;QAC9B,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAChC,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;KACpB;IAED,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"ax.js","sourceRoot":"","sources":["../../../src/runtime/ax.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,OAAO,UAAU,EAAE,CAAC,UAAiD;IAC1E,0BAA0B;IAC1B,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;QACtB,OAAO;KACR;IAED,yEAAyE;IACzE,IACE,UAAU,CAAC,MAAM,KAAK,CAAC;QACvB,UAAU,CAAC,CAAC,CAAC;QACb,gFAAgF;QAChF,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAC5B;QACA,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;KACtB;IAED,gFAAgF;IAChF,mFAAmF;IACnF,MAAM,GAAG,GAA2B,EAAE,CAAC;IAEvC,+DAA+D;IAC/D,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE;QAC9B,mEAAmE;QACnE,IAAI,CAAC,KAAK,EAAE;YACV,SAAS;SACV;QAED,4CAA4C;QAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE;YAC5B;;;;;;;;;;;;iBAYK;YACL,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5F,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;SACtB;KACF;IAED;;;;;;;OAOG;IACH,IAAI,MAAM,GAAW,EAAE,CAAC;IACxB,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;QACrB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;KAC1B;IAED,wDAAwD;IACxD,IAAI,CAAC,MAAM,EAAE;QACX,OAAO;KACR;IAED,2EAA2E;IAC3E,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC"}
@@ -27,7 +27,7 @@ export type CSSPseudos = CSSPseudoElements | CSSPseudoClasses;
27
27
  * excess property check doesn't enable makers to circumvent the
28
28
  * system and pass in values they shouldn't.
29
29
  */
30
- export type CSSProperties = Readonly<CSS.Properties<(string & object) | number>>;
30
+ export type CSSProperties = Readonly<CSS.Properties<(string & NonNullable<unknown>) | number>>;
31
31
  /**
32
32
  * A stricter subset of the {@link CSSProperties} type that excludes
33
33
  * vendor and obsolete properties.
@@ -1,22 +1,21 @@
1
1
  /**
2
- * Joins classes together and ensures atomic declarations of a single group exist.
3
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
4
- * where both `group` and `value` are hashes **four characters long**.
5
- * Class names can be of any length,
6
- * this function can take both atomic declarations and class names.
2
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
3
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
7
4
  *
8
- * Input:
9
- *
10
- * ```
11
- * ax(['_aaaabbbb', '_aaaacccc'])
5
+ * ```ts
6
+ * ax(['_aaaabbbb', '_aaaacccc']);
7
+ * // output
8
+ * '_aaaacccc'
12
9
  * ```
13
10
  *
14
- * Output:
11
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
15
12
  *
16
- * ```
17
- * '_aaaacccc'
18
- * ```
13
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
19
14
  *
20
- * @param classes
15
+ * ```ts
16
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
17
+ * // output
18
+ * '_aaaacccc border-red'
19
+ * ```
21
20
  */
22
21
  export default function ax(classNames: (string | undefined | null | false)[]): string | undefined;
@@ -1,56 +1,89 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const UNDERSCORE_UNICODE = 95;
4
3
  /**
5
4
  * This length includes the underscore,
6
5
  * e.g. `"_1s4A"` would be a valid atomic group hash.
7
6
  */
8
7
  const ATOMIC_GROUP_LENGTH = 5;
9
8
  /**
10
- * Joins classes together and ensures atomic declarations of a single group exist.
11
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
12
- * where both `group` and `value` are hashes **four characters long**.
13
- * Class names can be of any length,
14
- * this function can take both atomic declarations and class names.
9
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
10
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
15
11
  *
16
- * Input:
17
- *
18
- * ```
19
- * ax(['_aaaabbbb', '_aaaacccc'])
12
+ * ```ts
13
+ * ax(['_aaaabbbb', '_aaaacccc']);
14
+ * // output
15
+ * '_aaaacccc'
20
16
  * ```
21
17
  *
22
- * Output:
18
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
23
19
  *
24
- * ```
25
- * '_aaaacccc'
26
- * ```
20
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
27
21
  *
28
- * @param classes
22
+ * ```ts
23
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
24
+ * // output
25
+ * '_aaaacccc border-red'
26
+ * ```
29
27
  */
30
28
  function ax(classNames) {
31
- if (classNames.length <= 1 && (!classNames[0] || classNames[0].indexOf(' ') === -1)) {
32
- // short circuit if there's no custom class names.
33
- return classNames[0] || undefined;
29
+ // Shortcut: nothing to do
30
+ if (!classNames.length) {
31
+ return;
34
32
  }
35
- const atomicGroups = {};
36
- for (let i = 0; i < classNames.length; i++) {
37
- const cls = classNames[i];
38
- if (!cls) {
33
+ // Shortcut: don't need to do anything if we only have a single classname
34
+ if (classNames.length === 1 &&
35
+ classNames[0] &&
36
+ // checking to see if `classNames[0]` is a string that contains other classnames
37
+ !classNames[0].includes(' ')) {
38
+ return classNames[0];
39
+ }
40
+ // Using an object rather than a `Map` as it performed better in our benchmarks.
41
+ // Would be happy to move to `Map` if it proved to be better under real conditions.
42
+ const map = {};
43
+ // Note: using loops to minimize iterations over the collection
44
+ for (const value of classNames) {
45
+ // Exclude all falsy values, which leaves us with populated strings
46
+ if (!value) {
39
47
  continue;
40
48
  }
41
- const groups = cls.split(' ');
42
- for (let x = 0; x < groups.length; x++) {
43
- const atomic = groups[x];
44
- const atomicGroupName = atomic.slice(0, atomic.charCodeAt(0) === UNDERSCORE_UNICODE ? ATOMIC_GROUP_LENGTH : undefined);
45
- atomicGroups[atomicGroupName] = atomic;
49
+ // a `value` can contain multiple classnames
50
+ const list = value.split(' ');
51
+ for (const className of list) {
52
+ /**
53
+ * For atomic style classnames: the `key` is the `group`
54
+ *
55
+ * - Later atomic classnames with the same `group` will override earlier ones
56
+ * (which is what we want).
57
+ * - Assumes atomic classnames are the only things that start with `_`
58
+ * - Could use a regex to ensure that atomic classnames are structured how we expect,
59
+ * but did not add that for now as it did slow things down a bit.
60
+ *
61
+ * For other classnames: the `key` is the whole classname
62
+ * - Okay to remove duplicates as doing so does not impact specificity
63
+ *
64
+ * */
65
+ const key = className.startsWith('_') ? className.slice(0, ATOMIC_GROUP_LENGTH) : className;
66
+ map[key] = className;
46
67
  }
47
68
  }
48
- let str = '';
49
- for (const key in atomicGroups) {
50
- const value = atomicGroups[key];
51
- str += value + ' ';
69
+ /**
70
+ * We are converting the `map` into a string.
71
+ *
72
+ * The simple way to do this would be `Object.values(map).join(' ')`.
73
+ * However, the approach below performs 10%-20% better in benchmarks.
74
+ *
75
+ * For `ax()` it feels right to squeeze as much runtime performance out as we can.
76
+ */
77
+ let result = '';
78
+ for (const key in map) {
79
+ result += map[key] + ' ';
80
+ }
81
+ // If we have an empty string, then our `map` was empty.
82
+ if (!result) {
83
+ return;
52
84
  }
53
- return str.slice(0, -1);
85
+ // remove last " " from the result (we added " " at the end of every value)
86
+ return result.trimEnd();
54
87
  }
55
88
  exports.default = ax;
56
89
  //# sourceMappingURL=ax.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ax.js","sourceRoot":"","sources":["../../../src/runtime/ax.ts"],"names":[],"mappings":";;AAAA,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAwB,EAAE,CAAC,UAAiD;IAC1E,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACnF,kDAAkD;QAClD,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;KACnC;IAED,MAAM,YAAY,GAA2B,EAAE,CAAC;IAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE;YACR,SAAS;SACV;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAClC,CAAC,EACD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAC9E,CAAC;YACF,YAAY,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;SACxC;KACF;IAED,IAAI,GAAG,GAAG,EAAE,CAAC;IAEb,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;QAC9B,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAChC,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;KACpB;IAED,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAlCD,qBAkCC"}
1
+ {"version":3,"file":"ax.js","sourceRoot":"","sources":["../../../src/runtime/ax.ts"],"names":[],"mappings":";;AAAA;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAwB,EAAE,CAAC,UAAiD;IAC1E,0BAA0B;IAC1B,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;QACtB,OAAO;KACR;IAED,yEAAyE;IACzE,IACE,UAAU,CAAC,MAAM,KAAK,CAAC;QACvB,UAAU,CAAC,CAAC,CAAC;QACb,gFAAgF;QAChF,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAC5B;QACA,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;KACtB;IAED,gFAAgF;IAChF,mFAAmF;IACnF,MAAM,GAAG,GAA2B,EAAE,CAAC;IAEvC,+DAA+D;IAC/D,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE;QAC9B,mEAAmE;QACnE,IAAI,CAAC,KAAK,EAAE;YACV,SAAS;SACV;QAED,4CAA4C;QAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE;YAC5B;;;;;;;;;;;;iBAYK;YACL,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5F,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;SACtB;KACF;IAED;;;;;;;OAOG;IACH,IAAI,MAAM,GAAW,EAAE,CAAC;IACxB,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;QACrB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;KAC1B;IAED,wDAAwD;IACxD,IAAI,CAAC,MAAM,EAAE;QACX,OAAO;KACR;IAED,2EAA2E;IAC3E,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AArED,qBAqEC"}
@@ -27,7 +27,7 @@ export type CSSPseudos = CSSPseudoElements | CSSPseudoClasses;
27
27
  * excess property check doesn't enable makers to circumvent the
28
28
  * system and pass in values they shouldn't.
29
29
  */
30
- export type CSSProperties = Readonly<CSS.Properties<(string & object) | number>>;
30
+ export type CSSProperties = Readonly<CSS.Properties<(string & NonNullable<unknown>) | number>>;
31
31
  /**
32
32
  * A stricter subset of the {@link CSSProperties} type that excludes
33
33
  * vendor and obsolete properties.
@@ -1,22 +1,21 @@
1
1
  /**
2
- * Joins classes together and ensures atomic declarations of a single group exist.
3
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
4
- * where both `group` and `value` are hashes **four characters long**.
5
- * Class names can be of any length,
6
- * this function can take both atomic declarations and class names.
2
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
3
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
7
4
  *
8
- * Input:
9
- *
10
- * ```
11
- * ax(['_aaaabbbb', '_aaaacccc'])
5
+ * ```ts
6
+ * ax(['_aaaabbbb', '_aaaacccc']);
7
+ * // output
8
+ * '_aaaacccc'
12
9
  * ```
13
10
  *
14
- * Output:
11
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
15
12
  *
16
- * ```
17
- * '_aaaacccc'
18
- * ```
13
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
19
14
  *
20
- * @param classes
15
+ * ```ts
16
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
17
+ * // output
18
+ * '_aaaacccc border-red'
19
+ * ```
21
20
  */
22
21
  export default function ax(classNames: (string | undefined | null | false)[]): string | undefined;
@@ -1,53 +1,86 @@
1
- const UNDERSCORE_UNICODE = 95;
2
1
  /**
3
2
  * This length includes the underscore,
4
3
  * e.g. `"_1s4A"` would be a valid atomic group hash.
5
4
  */
6
5
  const ATOMIC_GROUP_LENGTH = 5;
7
6
  /**
8
- * Joins classes together and ensures atomic declarations of a single group exist.
9
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
10
- * where both `group` and `value` are hashes **four characters long**.
11
- * Class names can be of any length,
12
- * this function can take both atomic declarations and class names.
7
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
8
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
13
9
  *
14
- * Input:
15
- *
16
- * ```
17
- * ax(['_aaaabbbb', '_aaaacccc'])
10
+ * ```ts
11
+ * ax(['_aaaabbbb', '_aaaacccc']);
12
+ * // output
13
+ * '_aaaacccc'
18
14
  * ```
19
15
  *
20
- * Output:
16
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
21
17
  *
22
- * ```
23
- * '_aaaacccc'
24
- * ```
18
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
25
19
  *
26
- * @param classes
20
+ * ```ts
21
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
22
+ * // output
23
+ * '_aaaacccc border-red'
24
+ * ```
27
25
  */
28
26
  export default function ax(classNames) {
29
- if (classNames.length <= 1 && (!classNames[0] || classNames[0].indexOf(' ') === -1)) {
30
- // short circuit if there's no custom class names.
31
- return classNames[0] || undefined;
27
+ // Shortcut: nothing to do
28
+ if (!classNames.length) {
29
+ return;
32
30
  }
33
- const atomicGroups = {};
34
- for (let i = 0; i < classNames.length; i++) {
35
- const cls = classNames[i];
36
- if (!cls) {
31
+ // Shortcut: don't need to do anything if we only have a single classname
32
+ if (classNames.length === 1 &&
33
+ classNames[0] &&
34
+ // checking to see if `classNames[0]` is a string that contains other classnames
35
+ !classNames[0].includes(' ')) {
36
+ return classNames[0];
37
+ }
38
+ // Using an object rather than a `Map` as it performed better in our benchmarks.
39
+ // Would be happy to move to `Map` if it proved to be better under real conditions.
40
+ const map = {};
41
+ // Note: using loops to minimize iterations over the collection
42
+ for (const value of classNames) {
43
+ // Exclude all falsy values, which leaves us with populated strings
44
+ if (!value) {
37
45
  continue;
38
46
  }
39
- const groups = cls.split(' ');
40
- for (let x = 0; x < groups.length; x++) {
41
- const atomic = groups[x];
42
- const atomicGroupName = atomic.slice(0, atomic.charCodeAt(0) === UNDERSCORE_UNICODE ? ATOMIC_GROUP_LENGTH : undefined);
43
- atomicGroups[atomicGroupName] = atomic;
47
+ // a `value` can contain multiple classnames
48
+ const list = value.split(' ');
49
+ for (const className of list) {
50
+ /**
51
+ * For atomic style classnames: the `key` is the `group`
52
+ *
53
+ * - Later atomic classnames with the same `group` will override earlier ones
54
+ * (which is what we want).
55
+ * - Assumes atomic classnames are the only things that start with `_`
56
+ * - Could use a regex to ensure that atomic classnames are structured how we expect,
57
+ * but did not add that for now as it did slow things down a bit.
58
+ *
59
+ * For other classnames: the `key` is the whole classname
60
+ * - Okay to remove duplicates as doing so does not impact specificity
61
+ *
62
+ * */
63
+ const key = className.startsWith('_') ? className.slice(0, ATOMIC_GROUP_LENGTH) : className;
64
+ map[key] = className;
44
65
  }
45
66
  }
46
- let str = '';
47
- for (const key in atomicGroups) {
48
- const value = atomicGroups[key];
49
- str += value + ' ';
67
+ /**
68
+ * We are converting the `map` into a string.
69
+ *
70
+ * The simple way to do this would be `Object.values(map).join(' ')`.
71
+ * However, the approach below performs 10%-20% better in benchmarks.
72
+ *
73
+ * For `ax()` it feels right to squeeze as much runtime performance out as we can.
74
+ */
75
+ let result = '';
76
+ for (const key in map) {
77
+ result += map[key] + ' ';
78
+ }
79
+ // If we have an empty string, then our `map` was empty.
80
+ if (!result) {
81
+ return;
50
82
  }
51
- return str.slice(0, -1);
83
+ // remove last " " from the result (we added " " at the end of every value)
84
+ return result.trimEnd();
52
85
  }
53
86
  //# sourceMappingURL=ax.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ax.js","sourceRoot":"","sources":["../../../src/runtime/ax.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAE9B;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,OAAO,UAAU,EAAE,CAAC,UAAiD;IAC1E,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACnF,kDAAkD;QAClD,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;KACnC;IAED,MAAM,YAAY,GAA2B,EAAE,CAAC;IAEhD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,EAAE;YACR,SAAS;SACV;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAClC,CAAC,EACD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAC9E,CAAC;YACF,YAAY,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC;SACxC;KACF;IAED,IAAI,GAAG,GAAG,EAAE,CAAC;IAEb,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;QAC9B,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAChC,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;KACpB;IAED,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"ax.js","sourceRoot":"","sources":["../../../src/runtime/ax.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,OAAO,UAAU,EAAE,CAAC,UAAiD;IAC1E,0BAA0B;IAC1B,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;QACtB,OAAO;KACR;IAED,yEAAyE;IACzE,IACE,UAAU,CAAC,MAAM,KAAK,CAAC;QACvB,UAAU,CAAC,CAAC,CAAC;QACb,gFAAgF;QAChF,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAC5B;QACA,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;KACtB;IAED,gFAAgF;IAChF,mFAAmF;IACnF,MAAM,GAAG,GAA2B,EAAE,CAAC;IAEvC,+DAA+D;IAC/D,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE;QAC9B,mEAAmE;QACnE,IAAI,CAAC,KAAK,EAAE;YACV,SAAS;SACV;QAED,4CAA4C;QAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE9B,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE;YAC5B;;;;;;;;;;;;iBAYK;YACL,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC5F,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;SACtB;KACF;IAED;;;;;;;OAOG;IACH,IAAI,MAAM,GAAW,EAAE,CAAC;IACxB,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE;QACrB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;KAC1B;IAED,wDAAwD;IACxD,IAAI,CAAC,MAAM,EAAE;QACX,OAAO;KACR;IAED,2EAA2E;IAC3E,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC"}
@@ -27,7 +27,7 @@ export type CSSPseudos = CSSPseudoElements | CSSPseudoClasses;
27
27
  * excess property check doesn't enable makers to circumvent the
28
28
  * system and pass in values they shouldn't.
29
29
  */
30
- export type CSSProperties = Readonly<CSS.Properties<(string & object) | number>>;
30
+ export type CSSProperties = Readonly<CSS.Properties<(string & NonNullable<unknown>) | number>>;
31
31
  /**
32
32
  * A stricter subset of the {@link CSSProperties} type that excludes
33
33
  * vendor and obsolete properties.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compiled/react",
3
- "version": "0.18.2",
3
+ "version": "0.18.4",
4
4
  "description": "A familiar and performant compile time CSS-in-JS library for React.",
5
5
  "keywords": [
6
6
  "compiled",
@@ -81,7 +81,7 @@
81
81
  "@testing-library/react": "^12.1.5",
82
82
  "@types/jsdom": "^16.2.15",
83
83
  "@types/react-dom": "^17.0.22",
84
- "expect-type": "^0.17.3",
84
+ "expect-type": "^0.20.0",
85
85
  "jsdom": "^19.0.0",
86
86
  "react": "^17.0.2",
87
87
  "react-dom": "^17.0.2"
@@ -18,6 +18,19 @@ describe('toHaveCompliedCss', () => {
18
18
  expect(getByText('hello world')).toHaveCompiledCss('font-size', '12px');
19
19
  });
20
20
 
21
+ it('should detect styles (SVG)', () => {
22
+ const { getByText } = render(
23
+ <svg
24
+ css={{
25
+ fontSize: '12px',
26
+ }}>
27
+ hello world
28
+ </svg>
29
+ );
30
+
31
+ expect(getByText('hello world')).toHaveCompiledCss('font-size', '12px');
32
+ });
33
+
21
34
  it('should detect missing styles', () => {
22
35
  const { getByText } = render(<div css={{ fontSize: '12px' }}>hello world</div>);
23
36
 
@@ -3,42 +3,61 @@ import { runBenchmark } from '@compiled/benchmark';
3
3
  import { ax } from '../index';
4
4
 
5
5
  describe('ax benchmark', () => {
6
- const arr = [
7
- '_19itglyw',
8
- '_2rko1l7b',
9
- '_ca0qftgi',
10
- '_u5f319bv',
11
- '_n3tdftgi',
12
- '_19bv19bv',
13
- '_bfhk1mzw',
14
- '_syazu67f',
15
- '_k48p1nn1',
16
- '_ect41kw7',
17
- '_1wybdlk8',
18
- '_irr3mlcl',
19
- '_1di6vctu',
20
- // `undefined` is an acceptable parameter so we want to include it in the test case.
21
- // Example: ax(['aaaabbbb', foo() && "aaaacccc"])
22
- undefined,
6
+ const chunks: string[] = ['aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff', 'gggg'];
7
+ const uniques: string[] = chunks.map((chunk) => `_${chunk}${chunk}`);
8
+ const withClashes: string[] = [
9
+ ...Array.from({ length: 4 }, () => `_${chunks[0]}${chunks[0]}`),
10
+ ...Array.from({ length: 6 }, () => `_${chunks[0]}${chunks[1]}`),
11
+ ...Array.from({ length: 8 }, () => `_${chunks[0]}${chunks[2]}`),
23
12
  ];
24
13
 
25
- it('completes with ax() string as the fastest', async () => {
26
- // Remove undefined and join the strings
27
- const str = arr.slice(0, -1).join(' ');
14
+ const getRandomRules = (() => {
15
+ function randomChunk() {
16
+ return chunks[Math.floor(Math.random() * chunks.length)];
17
+ }
18
+
19
+ return function create(): string[] {
20
+ return Array.from({ length: 20 }, () => `_${randomChunk()}${randomChunk()}`);
21
+ };
22
+ })();
28
23
 
24
+ it('completes with ax() string as the fastest', async () => {
29
25
  const benchmark = await runBenchmark('ax', [
30
26
  {
31
- name: 'ax() array',
32
- fn: () => ax(arr),
27
+ name: 'ax() single',
28
+ fn: () => ax(['_aaaabbbb']),
29
+ },
30
+ {
31
+ name: 'ax() uniques (array)',
32
+ fn: () => ax(uniques),
33
+ },
34
+ {
35
+ name: 'ax() uniques (as a string)',
36
+ fn: () => ax([uniques.join(' ')]),
37
+ },
38
+ {
39
+ name: 'ax() clashes',
40
+ fn: () => ax(withClashes),
41
+ },
42
+ {
43
+ name: 'ax() clashes (as a string)',
44
+ fn: () => ax([withClashes.join(' ')]),
45
+ },
46
+ {
47
+ name: 'ax() random keys (no clashes)',
48
+ fn: () => ax(getRandomRules()),
33
49
  },
34
50
  {
35
- name: 'ax() string',
36
- fn: () => ax([str, undefined]),
51
+ name: 'ax() random keys (with clashes)',
52
+ fn: () => {
53
+ const random = getRandomRules();
54
+ ax([...random, ...random, ...random]);
55
+ },
37
56
  },
38
57
  ]);
39
58
 
40
59
  expect(benchmark).toMatchObject({
41
- fastest: ['ax() string'],
60
+ fastest: ['ax() single'],
42
61
  });
43
- }, 30000);
62
+ }, 90000);
44
63
  });
@@ -6,6 +6,7 @@ describe('ax', () => {
6
6
  it.each([
7
7
  ['should handle empty array', [], undefined],
8
8
  ['should handle array with undefined', [undefined], undefined],
9
+ ['should handle array with falsy values', [undefined, null, false as const, ''], undefined],
9
10
  ['should join single classes together', ['foo', 'bar'], 'foo bar'],
10
11
  ['should join multi classes together', ['foo baz', 'bar'], 'foo baz bar'],
11
12
  ['should remove undefined', ['foo', 'bar', undefined], 'foo bar'],
@@ -50,7 +51,8 @@ describe('ax', () => {
50
51
  ['hello_there', 'hello_world', '_aaaabbbb'],
51
52
  'hello_there hello_world _aaaabbbb',
52
53
  ],
53
- ])('%s', (_, params, result) => {
54
- expect(result).toEqual(ax(params));
54
+ ['should remove duplicate custom class names', ['a', 'a'], 'a'],
55
+ ])('%s', (_, params, expected) => {
56
+ expect(ax(params)).toEqual(expected);
55
57
  });
56
58
  });
package/src/runtime/ax.ts CHANGED
@@ -1,5 +1,3 @@
1
- const UNDERSCORE_UNICODE = 95;
2
-
3
1
  /**
4
2
  * This length includes the underscore,
5
3
  * e.g. `"_1s4A"` would be a valid atomic group hash.
@@ -7,58 +5,92 @@ const UNDERSCORE_UNICODE = 95;
7
5
  const ATOMIC_GROUP_LENGTH = 5;
8
6
 
9
7
  /**
10
- * Joins classes together and ensures atomic declarations of a single group exist.
11
- * Atomic declarations take the form of `_{group}{value}` (always prefixed with an underscore),
12
- * where both `group` and `value` are hashes **four characters long**.
13
- * Class names can be of any length,
14
- * this function can take both atomic declarations and class names.
15
- *
16
- * Input:
8
+ * Create a single string containing all the classnames provided, separated by a space (`" "`).
9
+ * The result will only contain the _last_ atomic style classname for each atomic `group`.
17
10
  *
18
- * ```
19
- * ax(['_aaaabbbb', '_aaaacccc'])
11
+ * ```ts
12
+ * ax(['_aaaabbbb', '_aaaacccc']);
13
+ * // output
14
+ * '_aaaacccc'
20
15
  * ```
21
16
  *
22
- * Output:
17
+ * Format of Atomic style classnames: `_{group}{value}` (`_\w{4}\w{4}`)
23
18
  *
24
- * ```
25
- * '_aaaacccc'
26
- * ```
19
+ * `ax` will preserve any non atomic style classnames (eg `"border-red"`)
27
20
  *
28
- * @param classes
21
+ * ```ts
22
+ * ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
23
+ * // output
24
+ * '_aaaacccc border-red'
25
+ * ```
29
26
  */
30
27
  export default function ax(classNames: (string | undefined | null | false)[]): string | undefined {
31
- if (classNames.length <= 1 && (!classNames[0] || classNames[0].indexOf(' ') === -1)) {
32
- // short circuit if there's no custom class names.
33
- return classNames[0] || undefined;
28
+ // Shortcut: nothing to do
29
+ if (!classNames.length) {
30
+ return;
34
31
  }
35
32
 
36
- const atomicGroups: Record<string, string> = {};
33
+ // Shortcut: don't need to do anything if we only have a single classname
34
+ if (
35
+ classNames.length === 1 &&
36
+ classNames[0] &&
37
+ // checking to see if `classNames[0]` is a string that contains other classnames
38
+ !classNames[0].includes(' ')
39
+ ) {
40
+ return classNames[0];
41
+ }
37
42
 
38
- for (let i = 0; i < classNames.length; i++) {
39
- const cls = classNames[i];
40
- if (!cls) {
43
+ // Using an object rather than a `Map` as it performed better in our benchmarks.
44
+ // Would be happy to move to `Map` if it proved to be better under real conditions.
45
+ const map: Record<string, string> = {};
46
+
47
+ // Note: using loops to minimize iterations over the collection
48
+ for (const value of classNames) {
49
+ // Exclude all falsy values, which leaves us with populated strings
50
+ if (!value) {
41
51
  continue;
42
52
  }
43
53
 
44
- const groups = cls.split(' ');
54
+ // a `value` can contain multiple classnames
55
+ const list = value.split(' ');
45
56
 
46
- for (let x = 0; x < groups.length; x++) {
47
- const atomic = groups[x];
48
- const atomicGroupName = atomic.slice(
49
- 0,
50
- atomic.charCodeAt(0) === UNDERSCORE_UNICODE ? ATOMIC_GROUP_LENGTH : undefined
51
- );
52
- atomicGroups[atomicGroupName] = atomic;
57
+ for (const className of list) {
58
+ /**
59
+ * For atomic style classnames: the `key` is the `group`
60
+ *
61
+ * - Later atomic classnames with the same `group` will override earlier ones
62
+ * (which is what we want).
63
+ * - Assumes atomic classnames are the only things that start with `_`
64
+ * - Could use a regex to ensure that atomic classnames are structured how we expect,
65
+ * but did not add that for now as it did slow things down a bit.
66
+ *
67
+ * For other classnames: the `key` is the whole classname
68
+ * - Okay to remove duplicates as doing so does not impact specificity
69
+ *
70
+ * */
71
+ const key = className.startsWith('_') ? className.slice(0, ATOMIC_GROUP_LENGTH) : className;
72
+ map[key] = className;
53
73
  }
54
74
  }
55
75
 
56
- let str = '';
76
+ /**
77
+ * We are converting the `map` into a string.
78
+ *
79
+ * The simple way to do this would be `Object.values(map).join(' ')`.
80
+ * However, the approach below performs 10%-20% better in benchmarks.
81
+ *
82
+ * For `ax()` it feels right to squeeze as much runtime performance out as we can.
83
+ */
84
+ let result: string = '';
85
+ for (const key in map) {
86
+ result += map[key] + ' ';
87
+ }
57
88
 
58
- for (const key in atomicGroups) {
59
- const value = atomicGroups[key];
60
- str += value + ' ';
89
+ // If we have an empty string, then our `map` was empty.
90
+ if (!result) {
91
+ return;
61
92
  }
62
93
 
63
- return str.slice(0, -1);
94
+ // remove last " " from the result (we added " " at the end of every value)
95
+ return result.trimEnd();
64
96
  }
package/src/types.ts CHANGED
@@ -104,7 +104,7 @@ export type CSSPseudos = CSSPseudoElements | CSSPseudoClasses;
104
104
  * excess property check doesn't enable makers to circumvent the
105
105
  * system and pass in values they shouldn't.
106
106
  */
107
- export type CSSProperties = Readonly<CSS.Properties<(string & object) | number>>;
107
+ export type CSSProperties = Readonly<CSS.Properties<(string & NonNullable<unknown>) | number>>;
108
108
 
109
109
  /**
110
110
  * A stricter subset of the {@link CSSProperties} type that excludes