@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.
- package/dist/browser/create-strict-api/types.d.ts +5 -5
- package/dist/browser/runtime/ax.d.ts +13 -14
- package/dist/browser/runtime/ax.js +65 -32
- package/dist/browser/runtime/ax.js.map +1 -1
- package/dist/browser/types.d.ts +3 -1
- package/dist/browser/xcss-prop/index.d.ts +3 -3
- package/dist/cjs/create-strict-api/types.d.ts +5 -5
- package/dist/cjs/runtime/ax.d.ts +13 -14
- package/dist/cjs/runtime/ax.js +65 -32
- package/dist/cjs/runtime/ax.js.map +1 -1
- package/dist/cjs/types.d.ts +3 -1
- package/dist/cjs/xcss-prop/index.d.ts +3 -3
- package/dist/esm/create-strict-api/types.d.ts +5 -5
- package/dist/esm/runtime/ax.d.ts +13 -14
- package/dist/esm/runtime/ax.js +65 -32
- package/dist/esm/runtime/ax.js.map +1 -1
- package/dist/esm/types.d.ts +3 -1
- package/dist/esm/xcss-prop/index.d.ts +3 -3
- package/package.json +1 -1
- package/src/__tests__/browser.test.tsx +4 -3
- package/src/__tests__/jest-matcher.test.tsx +13 -0
- package/src/create-strict-api/__tests__/__fixtures__/strict-api-recursive.ts +6 -0
- package/src/create-strict-api/__tests__/generics.test.tsx +46 -4
- package/src/create-strict-api/types.ts +5 -5
- package/src/runtime/__perf__/ax.test.ts +45 -26
- package/src/runtime/__tests__/ax.test.ts +4 -2
- package/src/runtime/ax.ts +68 -36
- package/src/types.ts +14 -2
- package/src/xcss-prop/__tests__/xcss-prop.test.tsx +31 -0
- package/src/xcss-prop/index.ts +3 -3
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { StrictCSSProperties,
|
|
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
|
|
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
|
|
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
|
|
24
|
-
[TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* ax(['_aaaabbbb', '_aaaacccc']);
|
|
7
|
+
* // output
|
|
8
|
+
* '_aaaacccc'
|
|
12
9
|
* ```
|
|
13
10
|
*
|
|
14
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
9
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* ax(['_aaaabbbb', '_aaaacccc']);
|
|
12
|
+
* // output
|
|
13
|
+
* '_aaaacccc'
|
|
18
14
|
* ```
|
|
19
15
|
*
|
|
20
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
return
|
|
27
|
+
// Shortcut: nothing to do
|
|
28
|
+
if (!classNames.length) {
|
|
29
|
+
return;
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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
|
|
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"}
|
package/dist/browser/types.d.ts
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
24
|
-
[TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends
|
|
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>;
|
package/dist/cjs/runtime/ax.d.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* ax(['_aaaabbbb', '_aaaacccc']);
|
|
7
|
+
* // output
|
|
8
|
+
* '_aaaacccc'
|
|
12
9
|
* ```
|
|
13
10
|
*
|
|
14
|
-
*
|
|
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
|
-
*
|
|
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;
|
package/dist/cjs/runtime/ax.js
CHANGED
|
@@ -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
|
-
*
|
|
11
|
-
*
|
|
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
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* ax(['_aaaabbbb', '_aaaacccc']);
|
|
14
|
+
* // output
|
|
15
|
+
* '_aaaacccc'
|
|
20
16
|
* ```
|
|
21
17
|
*
|
|
22
|
-
*
|
|
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
|
-
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* ax(['_aaaabbbb', '_aaaacccc', 'border-red']);
|
|
24
|
+
* // output
|
|
25
|
+
* '_aaaacccc border-red'
|
|
26
|
+
* ```
|
|
29
27
|
*/
|
|
30
28
|
function ax(classNames) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
29
|
+
// Shortcut: nothing to do
|
|
30
|
+
if (!classNames.length) {
|
|
31
|
+
return;
|
|
34
32
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
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
|
|
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"}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
24
|
-
[TKey in keyof TObject]?: TKey extends keyof StrictCSSProperties ? ApplySchemaValue<TSchema, TKey, TPseudoKey> : TKey extends
|
|
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>;
|
package/dist/esm/runtime/ax.d.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* ax(['_aaaabbbb', '_aaaacccc']);
|
|
7
|
+
* // output
|
|
8
|
+
* '_aaaacccc'
|
|
12
9
|
* ```
|
|
13
10
|
*
|
|
14
|
-
*
|
|
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
|
-
*
|
|
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;
|