@compiled/react 0.18.3 → 0.18.5

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,11 +1,11 @@
1
- import type { StrictCSSProperties, CSSPseudoClasses, CSSPseudoElements, CSSPseudos } from '../types';
1
+ import type { StrictCSSProperties, CSSPseudoElements, CSSPseudos, AllCSSPseudoClasses } from '../types';
2
2
  /**
3
3
  * This is the shape of the generic object that `createStrictAPI()` takes.
4
4
  * It's deliberately a subset of `AllowedStyles` and does not take at rules
5
5
  * and pseudo elements.
6
6
  */
7
7
  export type CompiledSchemaShape = StrictCSSProperties & {
8
- [Q in CSSPseudoClasses]?: StrictCSSProperties;
8
+ [Q in AllCSSPseudoClasses]?: StrictCSSProperties;
9
9
  };
10
10
  export type PseudosDeclarations = {
11
11
  [Q in CSSPseudos]?: StrictCSSProperties;
@@ -14,14 +14,14 @@ export type MediaQueries<TMediaQuery extends string> = {
14
14
  [Q in `@media ${TMediaQuery}`]?: StrictCSSProperties & PseudosDeclarations;
15
15
  };
16
16
  export type AllowedStyles<TMediaQuery extends string> = StrictCSSProperties & PseudosDeclarations & MediaQueries<TMediaQuery>;
17
- export type ApplySchemaValue<TSchema, TKey extends keyof StrictCSSProperties, TPseudoKey extends CSSPseudoClasses | ''> = TKey extends keyof TSchema ? TPseudoKey extends keyof TSchema ? TKey extends keyof TSchema[TPseudoKey] ? TSchema[TPseudoKey][TKey] : TSchema[TKey] : TSchema[TKey] : StrictCSSProperties[TKey];
17
+ export type ApplySchemaValue<TSchema, TKey extends keyof StrictCSSProperties, TPseudoKey extends AllCSSPseudoClasses | ''> = TKey extends keyof TSchema ? TPseudoKey extends keyof TSchema ? TKey extends keyof TSchema[TPseudoKey] ? TSchema[TPseudoKey][TKey] : TSchema[TKey] : TSchema[TKey] : StrictCSSProperties[TKey];
18
18
  /**
19
19
  * Recursively maps over object properties to resolve them to either a {@link TSchema}
20
20
  * value if present, else fallback to its value from {@link StrictCSSProperties}. If
21
21
  * the property isn't a known property its value will be resolved to `never`.
22
22
  */
23
- export type ApplySchema<TObject, TSchema, TPseudoKey extends CSSPseudoClasses | '' = ''> = {
24
- [TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends CSSPseudoClasses ? ApplySchema<TObject[TKey], TSchema, TKey> : TKey extends `@${string}` | CSSPseudoElements ? ApplySchema<TObject[TKey], TSchema> : never;
23
+ export type ApplySchema<TObject, TSchema, TPseudoKey extends AllCSSPseudoClasses | '' = ''> = {
24
+ [TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends AllCSSPseudoClasses ? ApplySchema<TObject[TKey], TSchema, TKey> : TKey extends `@${string}` | CSSPseudoElements ? ApplySchema<TObject[TKey], TSchema> : never;
25
25
  };
26
26
  export type ApplySchemaMap<TStylesMap, TSchema> = {
27
27
  [P in keyof TStylesMap]: ApplySchema<TStylesMap[P], TSchema>;
@@ -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"}
@@ -19,8 +19,10 @@ export type CssObject<TProps> = Readonly<{
19
19
  }>;
20
20
  export type CssFunction<TProps = unknown> = CssType<TProps> | BasicTemplateInterpolations | null | boolean | undefined;
21
21
  export type CSSPseudoElements = '&::after' | '&::backdrop' | '&::before' | '&::cue' | '&::cue-region' | '&::first-letter' | '&::first-line' | '&::grammar-error' | '&::marker' | '&::placeholder' | '&::selection' | '&::spelling-error' | '&::target-text' | '&::view-transition';
22
+ export type FlattenedChainedCSSPseudosClasses = '&:visited:active' | '&:visited:hover' | '&:active:visited' | '&:hover::before' | '&:hover::after' | '&:focus-visible::before' | '&:focus-visible::after' | '&:focus:not(:focus-visible)';
22
23
  export type CSSPseudoClasses = '&:active' | '&:autofill' | '&:blank' | '&:checked' | '&:default' | '&:defined' | '&:disabled' | '&:empty' | '&:enabled' | '&:first' | '&:focus' | '&:focus-visible' | '&:focus-within' | '&:fullscreen' | '&:hover' | '&:in-range' | '&:indeterminate' | '&:invalid' | '&:left' | '&:link' | '&:local-link' | '&:optional' | '&:out-of-range' | '&:paused' | '&:picture-in-picture' | '&:placeholder-shown' | '&:playing' | '&:read-only' | '&:read-write' | '&:required' | '&:right' | '&:target' | '&:user-invalid' | '&:user-valid' | '&:valid' | '&:visited';
23
- export type CSSPseudos = CSSPseudoElements | CSSPseudoClasses;
24
+ export type AllCSSPseudoClasses = CSSPseudoClasses | FlattenedChainedCSSPseudosClasses;
25
+ export type CSSPseudos = CSSPseudoElements | AllCSSPseudoClasses;
24
26
  /**
25
27
  * The XCSSProp must be given all known available properties even
26
28
  * if it takes a subset of them. This ensures the (lack-of an)
@@ -1,16 +1,16 @@
1
1
  import type * as CSS from 'csstype';
2
2
  import type { ApplySchemaValue } from '../create-strict-api/types';
3
- import type { CSSPseudos, CSSPseudoClasses, CSSProperties, StrictCSSProperties } from '../types';
3
+ import type { CSSPseudos, CSSProperties, StrictCSSProperties, AllCSSPseudoClasses } from '../types';
4
4
  type MarkAsRequired<T, K extends keyof T> = T & {
5
5
  [P in K]-?: T[P];
6
6
  };
7
- type XCSSValue<TStyleDecl extends keyof CSSProperties, TSchema, TPseudoKey extends CSSPseudoClasses | ''> = {
7
+ type XCSSValue<TStyleDecl extends keyof CSSProperties, TSchema, TPseudoKey extends AllCSSPseudoClasses | ''> = {
8
8
  [Q in keyof StrictCSSProperties]: Q extends TStyleDecl ? ApplySchemaValue<TSchema, Q, TPseudoKey> : never;
9
9
  };
10
10
  type XCSSPseudo<TAllowedProperties extends keyof StrictCSSProperties, TAllowedPseudos extends CSSPseudos, TRequiredProperties extends {
11
11
  requiredProperties: TAllowedProperties;
12
12
  }, TSchema> = {
13
- [Q in CSSPseudos]?: Q extends TAllowedPseudos ? MarkAsRequired<XCSSValue<TAllowedProperties, TSchema, Q extends CSSPseudoClasses ? Q : ''>, TRequiredProperties['requiredProperties']> : never;
13
+ [Q in CSSPseudos]?: Q extends TAllowedPseudos ? MarkAsRequired<XCSSValue<TAllowedProperties, TSchema, Q extends AllCSSPseudoClasses ? Q : ''>, TRequiredProperties['requiredProperties']> : never;
14
14
  };
15
15
  type XCSSMediaQuery<TAllowedProperties extends keyof StrictCSSProperties, TAllowedPseudos extends CSSPseudos, TAllowedMediaQueries extends string, TSchema> = {
16
16
  [Q in `@media ${TAllowedMediaQueries}`]?: XCSSValue<TAllowedProperties, TSchema, ''> | XCSSPseudo<TAllowedProperties, TAllowedPseudos, never, TSchema>;
@@ -1,11 +1,11 @@
1
- import type { StrictCSSProperties, CSSPseudoClasses, CSSPseudoElements, CSSPseudos } from '../types';
1
+ import type { StrictCSSProperties, CSSPseudoElements, CSSPseudos, AllCSSPseudoClasses } from '../types';
2
2
  /**
3
3
  * This is the shape of the generic object that `createStrictAPI()` takes.
4
4
  * It's deliberately a subset of `AllowedStyles` and does not take at rules
5
5
  * and pseudo elements.
6
6
  */
7
7
  export type CompiledSchemaShape = StrictCSSProperties & {
8
- [Q in CSSPseudoClasses]?: StrictCSSProperties;
8
+ [Q in AllCSSPseudoClasses]?: StrictCSSProperties;
9
9
  };
10
10
  export type PseudosDeclarations = {
11
11
  [Q in CSSPseudos]?: StrictCSSProperties;
@@ -14,14 +14,14 @@ export type MediaQueries<TMediaQuery extends string> = {
14
14
  [Q in `@media ${TMediaQuery}`]?: StrictCSSProperties & PseudosDeclarations;
15
15
  };
16
16
  export type AllowedStyles<TMediaQuery extends string> = StrictCSSProperties & PseudosDeclarations & MediaQueries<TMediaQuery>;
17
- export type ApplySchemaValue<TSchema, TKey extends keyof StrictCSSProperties, TPseudoKey extends CSSPseudoClasses | ''> = TKey extends keyof TSchema ? TPseudoKey extends keyof TSchema ? TKey extends keyof TSchema[TPseudoKey] ? TSchema[TPseudoKey][TKey] : TSchema[TKey] : TSchema[TKey] : StrictCSSProperties[TKey];
17
+ export type ApplySchemaValue<TSchema, TKey extends keyof StrictCSSProperties, TPseudoKey extends AllCSSPseudoClasses | ''> = TKey extends keyof TSchema ? TPseudoKey extends keyof TSchema ? TKey extends keyof TSchema[TPseudoKey] ? TSchema[TPseudoKey][TKey] : TSchema[TKey] : TSchema[TKey] : StrictCSSProperties[TKey];
18
18
  /**
19
19
  * Recursively maps over object properties to resolve them to either a {@link TSchema}
20
20
  * value if present, else fallback to its value from {@link StrictCSSProperties}. If
21
21
  * the property isn't a known property its value will be resolved to `never`.
22
22
  */
23
- export type ApplySchema<TObject, TSchema, TPseudoKey extends CSSPseudoClasses | '' = ''> = {
24
- [TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends CSSPseudoClasses ? ApplySchema<TObject[TKey], TSchema, TKey> : TKey extends `@${string}` | CSSPseudoElements ? ApplySchema<TObject[TKey], TSchema> : never;
23
+ export type ApplySchema<TObject, TSchema, TPseudoKey extends AllCSSPseudoClasses | '' = ''> = {
24
+ [TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends AllCSSPseudoClasses ? ApplySchema<TObject[TKey], TSchema, TKey> : TKey extends `@${string}` | CSSPseudoElements ? ApplySchema<TObject[TKey], TSchema> : never;
25
25
  };
26
26
  export type ApplySchemaMap<TStylesMap, TSchema> = {
27
27
  [P in keyof TStylesMap]: ApplySchema<TStylesMap[P], TSchema>;
@@ -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"}
@@ -19,8 +19,10 @@ export type CssObject<TProps> = Readonly<{
19
19
  }>;
20
20
  export type CssFunction<TProps = unknown> = CssType<TProps> | BasicTemplateInterpolations | null | boolean | undefined;
21
21
  export type CSSPseudoElements = '&::after' | '&::backdrop' | '&::before' | '&::cue' | '&::cue-region' | '&::first-letter' | '&::first-line' | '&::grammar-error' | '&::marker' | '&::placeholder' | '&::selection' | '&::spelling-error' | '&::target-text' | '&::view-transition';
22
+ export type FlattenedChainedCSSPseudosClasses = '&:visited:active' | '&:visited:hover' | '&:active:visited' | '&:hover::before' | '&:hover::after' | '&:focus-visible::before' | '&:focus-visible::after' | '&:focus:not(:focus-visible)';
22
23
  export type CSSPseudoClasses = '&:active' | '&:autofill' | '&:blank' | '&:checked' | '&:default' | '&:defined' | '&:disabled' | '&:empty' | '&:enabled' | '&:first' | '&:focus' | '&:focus-visible' | '&:focus-within' | '&:fullscreen' | '&:hover' | '&:in-range' | '&:indeterminate' | '&:invalid' | '&:left' | '&:link' | '&:local-link' | '&:optional' | '&:out-of-range' | '&:paused' | '&:picture-in-picture' | '&:placeholder-shown' | '&:playing' | '&:read-only' | '&:read-write' | '&:required' | '&:right' | '&:target' | '&:user-invalid' | '&:user-valid' | '&:valid' | '&:visited';
23
- export type CSSPseudos = CSSPseudoElements | CSSPseudoClasses;
24
+ export type AllCSSPseudoClasses = CSSPseudoClasses | FlattenedChainedCSSPseudosClasses;
25
+ export type CSSPseudos = CSSPseudoElements | AllCSSPseudoClasses;
24
26
  /**
25
27
  * The XCSSProp must be given all known available properties even
26
28
  * if it takes a subset of them. This ensures the (lack-of an)
@@ -1,16 +1,16 @@
1
1
  import type * as CSS from 'csstype';
2
2
  import type { ApplySchemaValue } from '../create-strict-api/types';
3
- import type { CSSPseudos, CSSPseudoClasses, CSSProperties, StrictCSSProperties } from '../types';
3
+ import type { CSSPseudos, CSSProperties, StrictCSSProperties, AllCSSPseudoClasses } from '../types';
4
4
  type MarkAsRequired<T, K extends keyof T> = T & {
5
5
  [P in K]-?: T[P];
6
6
  };
7
- type XCSSValue<TStyleDecl extends keyof CSSProperties, TSchema, TPseudoKey extends CSSPseudoClasses | ''> = {
7
+ type XCSSValue<TStyleDecl extends keyof CSSProperties, TSchema, TPseudoKey extends AllCSSPseudoClasses | ''> = {
8
8
  [Q in keyof StrictCSSProperties]: Q extends TStyleDecl ? ApplySchemaValue<TSchema, Q, TPseudoKey> : never;
9
9
  };
10
10
  type XCSSPseudo<TAllowedProperties extends keyof StrictCSSProperties, TAllowedPseudos extends CSSPseudos, TRequiredProperties extends {
11
11
  requiredProperties: TAllowedProperties;
12
12
  }, TSchema> = {
13
- [Q in CSSPseudos]?: Q extends TAllowedPseudos ? MarkAsRequired<XCSSValue<TAllowedProperties, TSchema, Q extends CSSPseudoClasses ? Q : ''>, TRequiredProperties['requiredProperties']> : never;
13
+ [Q in CSSPseudos]?: Q extends TAllowedPseudos ? MarkAsRequired<XCSSValue<TAllowedProperties, TSchema, Q extends AllCSSPseudoClasses ? Q : ''>, TRequiredProperties['requiredProperties']> : never;
14
14
  };
15
15
  type XCSSMediaQuery<TAllowedProperties extends keyof StrictCSSProperties, TAllowedPseudos extends CSSPseudos, TAllowedMediaQueries extends string, TSchema> = {
16
16
  [Q in `@media ${TAllowedMediaQueries}`]?: XCSSValue<TAllowedProperties, TSchema, ''> | XCSSPseudo<TAllowedProperties, TAllowedPseudos, never, TSchema>;
@@ -1,11 +1,11 @@
1
- import type { StrictCSSProperties, CSSPseudoClasses, CSSPseudoElements, CSSPseudos } from '../types';
1
+ import type { StrictCSSProperties, CSSPseudoElements, CSSPseudos, AllCSSPseudoClasses } from '../types';
2
2
  /**
3
3
  * This is the shape of the generic object that `createStrictAPI()` takes.
4
4
  * It's deliberately a subset of `AllowedStyles` and does not take at rules
5
5
  * and pseudo elements.
6
6
  */
7
7
  export type CompiledSchemaShape = StrictCSSProperties & {
8
- [Q in CSSPseudoClasses]?: StrictCSSProperties;
8
+ [Q in AllCSSPseudoClasses]?: StrictCSSProperties;
9
9
  };
10
10
  export type PseudosDeclarations = {
11
11
  [Q in CSSPseudos]?: StrictCSSProperties;
@@ -14,14 +14,14 @@ export type MediaQueries<TMediaQuery extends string> = {
14
14
  [Q in `@media ${TMediaQuery}`]?: StrictCSSProperties & PseudosDeclarations;
15
15
  };
16
16
  export type AllowedStyles<TMediaQuery extends string> = StrictCSSProperties & PseudosDeclarations & MediaQueries<TMediaQuery>;
17
- export type ApplySchemaValue<TSchema, TKey extends keyof StrictCSSProperties, TPseudoKey extends CSSPseudoClasses | ''> = TKey extends keyof TSchema ? TPseudoKey extends keyof TSchema ? TKey extends keyof TSchema[TPseudoKey] ? TSchema[TPseudoKey][TKey] : TSchema[TKey] : TSchema[TKey] : StrictCSSProperties[TKey];
17
+ export type ApplySchemaValue<TSchema, TKey extends keyof StrictCSSProperties, TPseudoKey extends AllCSSPseudoClasses | ''> = TKey extends keyof TSchema ? TPseudoKey extends keyof TSchema ? TKey extends keyof TSchema[TPseudoKey] ? TSchema[TPseudoKey][TKey] : TSchema[TKey] : TSchema[TKey] : StrictCSSProperties[TKey];
18
18
  /**
19
19
  * Recursively maps over object properties to resolve them to either a {@link TSchema}
20
20
  * value if present, else fallback to its value from {@link StrictCSSProperties}. If
21
21
  * the property isn't a known property its value will be resolved to `never`.
22
22
  */
23
- export type ApplySchema<TObject, TSchema, TPseudoKey extends CSSPseudoClasses | '' = ''> = {
24
- [TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends CSSPseudoClasses ? ApplySchema<TObject[TKey], TSchema, TKey> : TKey extends `@${string}` | CSSPseudoElements ? ApplySchema<TObject[TKey], TSchema> : never;
23
+ export type ApplySchema<TObject, TSchema, TPseudoKey extends AllCSSPseudoClasses | '' = ''> = {
24
+ [TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends AllCSSPseudoClasses ? ApplySchema<TObject[TKey], TSchema, TKey> : TKey extends `@${string}` | CSSPseudoElements ? ApplySchema<TObject[TKey], TSchema> : never;
25
25
  };
26
26
  export type ApplySchemaMap<TStylesMap, TSchema> = {
27
27
  [P in keyof TStylesMap]: ApplySchema<TStylesMap[P], TSchema>;
@@ -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;