@compiled/react 0.16.1 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/browser/class-names/index.d.ts +1 -1
  2. package/dist/browser/create-strict-api/index.d.ts +181 -0
  3. package/dist/browser/create-strict-api/index.js +65 -0
  4. package/dist/browser/create-strict-api/index.js.map +1 -0
  5. package/dist/browser/css/index.d.ts +1 -1
  6. package/dist/browser/css-map/index.d.ts +3 -5
  7. package/dist/browser/css-map/index.js +3 -5
  8. package/dist/browser/css-map/index.js.map +1 -1
  9. package/dist/browser/index.d.ts +1 -0
  10. package/dist/browser/index.js +1 -0
  11. package/dist/browser/index.js.map +1 -1
  12. package/dist/browser/types.d.ts +7 -2
  13. package/dist/browser/xcss-prop/index.d.ts +14 -10
  14. package/dist/browser/xcss-prop/index.js +1 -1
  15. package/dist/browser/xcss-prop/index.js.map +1 -1
  16. package/dist/cjs/class-names/index.d.ts +1 -1
  17. package/dist/cjs/create-strict-api/index.d.ts +181 -0
  18. package/dist/cjs/create-strict-api/index.js +69 -0
  19. package/dist/cjs/create-strict-api/index.js.map +1 -0
  20. package/dist/cjs/css/index.d.ts +1 -1
  21. package/dist/cjs/css-map/index.d.ts +3 -5
  22. package/dist/cjs/css-map/index.js +3 -5
  23. package/dist/cjs/css-map/index.js.map +1 -1
  24. package/dist/cjs/index.d.ts +1 -0
  25. package/dist/cjs/index.js +3 -1
  26. package/dist/cjs/index.js.map +1 -1
  27. package/dist/cjs/types.d.ts +7 -2
  28. package/dist/cjs/xcss-prop/index.d.ts +14 -10
  29. package/dist/cjs/xcss-prop/index.js +1 -1
  30. package/dist/cjs/xcss-prop/index.js.map +1 -1
  31. package/dist/esm/class-names/index.d.ts +1 -1
  32. package/dist/esm/create-strict-api/index.d.ts +181 -0
  33. package/dist/esm/create-strict-api/index.js +65 -0
  34. package/dist/esm/create-strict-api/index.js.map +1 -0
  35. package/dist/esm/css/index.d.ts +1 -1
  36. package/dist/esm/css-map/index.d.ts +3 -5
  37. package/dist/esm/css-map/index.js +3 -5
  38. package/dist/esm/css-map/index.js.map +1 -1
  39. package/dist/esm/index.d.ts +1 -0
  40. package/dist/esm/index.js +1 -0
  41. package/dist/esm/index.js.map +1 -1
  42. package/dist/esm/types.d.ts +7 -2
  43. package/dist/esm/xcss-prop/index.d.ts +14 -10
  44. package/dist/esm/xcss-prop/index.js +1 -1
  45. package/dist/esm/xcss-prop/index.js.map +1 -1
  46. package/package.json +2 -1
  47. package/src/class-names/index.ts +1 -1
  48. package/src/create-strict-api/__tests__/__fixtures__/strict-api.ts +13 -0
  49. package/src/create-strict-api/__tests__/index.test.tsx +312 -0
  50. package/src/create-strict-api/__tests__/package.test.tsx +21 -0
  51. package/src/create-strict-api/index.ts +223 -0
  52. package/src/css/index.ts +1 -1
  53. package/src/css-map/index.ts +3 -5
  54. package/src/index.ts +1 -0
  55. package/src/types.ts +8 -2
  56. package/src/xcss-prop/index.ts +33 -10
@@ -1,12 +1,15 @@
1
1
  import type * as CSS from 'csstype';
2
2
  import type { CSSPseudos, CSSProperties } from '../types';
3
- type XCSSItem<TStyleDecl extends keyof CSSProperties> = {
4
- [Q in keyof CSSProperties]: Q extends TStyleDecl ? CompiledPropertyDeclarationReference | string | number : never;
3
+ type MarkAsRequired<T, K extends keyof T> = T & {
4
+ [P in K]-?: T[P];
5
+ };
6
+ type XCSSItem<TStyleDecl extends keyof CSSProperties, TCompiledTypedProperty> = {
7
+ [Q in keyof CSSProperties]: Q extends TStyleDecl ? CompiledPropertyDeclarationReference | (Q extends keyof TCompiledTypedProperty ? TCompiledTypedProperty[Q] : CSSProperties[Q]) : never;
5
8
  };
6
9
  type XCSSPseudos<TAllowedProperties extends keyof CSSProperties, TAllowedPseudos extends CSSPseudos, TRequiredProperties extends {
7
10
  requiredProperties: TAllowedProperties;
8
- }> = {
9
- [Q in CSSPseudos]?: Q extends TAllowedPseudos ? MarkAsRequired<XCSSItem<TAllowedProperties>, TRequiredProperties['requiredProperties']> : never;
11
+ }, TCompiledTypedPseudo> = {
12
+ [Q in CSSPseudos]?: Q extends TAllowedPseudos ? MarkAsRequired<XCSSItem<TAllowedProperties, Q extends keyof TCompiledTypedPseudo ? TCompiledTypedPseudo[Q] : object>, TRequiredProperties['requiredProperties']> : never;
10
13
  };
11
14
  /**
12
15
  * These APIs we don't want to allow to be passed through the `xcss` prop but we also
@@ -47,7 +50,7 @@ export type XCSSAllProperties = keyof CSSProperties;
47
50
  */
48
51
  export type XCSSAllPseudos = CSSPseudos;
49
52
  /**
50
- * ## xcss prop
53
+ * ## XCSSProp
51
54
  *
52
55
  * Declare styles your component takes with all other styles marked as violations
53
56
  * by the TypeScript compiler. There are two primary use cases for xcss prop:
@@ -106,12 +109,13 @@ export type XCSSAllPseudos = CSSPseudos;
106
109
  export type XCSSProp<TAllowedProperties extends keyof CSSProperties, TAllowedPseudos extends CSSPseudos, TRequiredProperties extends {
107
110
  requiredProperties: TAllowedProperties;
108
111
  requiredPseudos: TAllowedPseudos;
109
- } = never> = (MarkAsRequired<XCSSItem<TAllowedProperties>, TRequiredProperties['requiredProperties']> & MarkAsRequired<XCSSPseudos<TAllowedProperties, TAllowedPseudos, TRequiredProperties>, TRequiredProperties['requiredPseudos']> & BlockedRules) | false | null | undefined;
110
- type MarkAsRequired<T, K extends keyof T> = T & {
111
- [P in K]-?: T[P];
112
- };
112
+ } = never> = Internal$XCSSProp<TAllowedProperties, TAllowedPseudos, object, object, TRequiredProperties>;
113
+ export type Internal$XCSSProp<TAllowedProperties extends keyof CSSProperties, TAllowedPseudos extends CSSPseudos, TCompiledTypedProperty, TCompiledTypedPseudo, TRequiredProperties extends {
114
+ requiredProperties: TAllowedProperties;
115
+ requiredPseudos: TAllowedPseudos;
116
+ }> = (MarkAsRequired<XCSSItem<TAllowedProperties, TCompiledTypedProperty>, TRequiredProperties['requiredProperties']> & MarkAsRequired<XCSSPseudos<TAllowedProperties, TAllowedPseudos, TRequiredProperties, TCompiledTypedPseudo>, TRequiredProperties['requiredPseudos']> & BlockedRules) | false | null | undefined;
113
117
  /**
114
- * ## cx
118
+ * ## CX
115
119
  *
116
120
  * Use in conjunction with the {@link XCSSProp} to concatenate and conditionally apply
117
121
  * declared styles. Can only be used with the `cssMap()` and {@link XCSSProp} APIs.
@@ -1,6 +1,6 @@
1
1
  import { ac } from '../runtime';
2
2
  /**
3
- * ## cx
3
+ * ## CX
4
4
  *
5
5
  * Use in conjunction with the {@link XCSSProp} to concatenate and conditionally apply
6
6
  * declared styles. Can only be used with the `cssMap()` and {@link XCSSProp} APIs.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/xcss-prop/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAiJhC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,CAChB,GAAG,MAAe,EACD,EAAE;IACnB,2EAA2E;IAC3E,sDAAsD;IACtD,MAAM,YAAY,GAAG,MAA6B,CAAC;IAEnD,+EAA+E;IAC/E,kFAAkF;IAClF,OAAO,EAAE,CAAC,YAAY,CAAoB,CAAC;AAC7C,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/xcss-prop/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAwKhC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,CAChB,GAAG,MAAe,EACD,EAAE;IACnB,2EAA2E;IAC3E,sDAAsD;IACtD,MAAM,YAAY,GAAG,MAA6B,CAAC;IAEnD,+EAA+E;IAC/E,kFAAkF;IAClF,OAAO,EAAE,CAAC,YAAY,CAAoB,CAAC;AAC7C,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compiled/react",
3
- "version": "0.16.1",
3
+ "version": "0.16.3",
4
4
  "description": "A familiar and performant compile time CSS-in-JS library for React.",
5
5
  "keywords": [
6
6
  "compiled",
@@ -76,6 +76,7 @@
76
76
  },
77
77
  "devDependencies": {
78
78
  "@compiled/benchmark": "^1.1.0",
79
+ "@fixture/strict-api-test": "*",
79
80
  "@testing-library/react": "^12.1.5",
80
81
  "@types/jsdom": "^16.2.15",
81
82
  "@types/react-dom": "^17.0.22",
@@ -19,7 +19,7 @@ export interface ClassNamesProps<TProps> {
19
19
  }
20
20
 
21
21
  /**
22
- * ## Class names
22
+ * ## Class Names
23
23
  *
24
24
  * Use a component where styles are not necessarily used on a JSX element.
25
25
  * For further details [read the documentation](https://compiledcssinjs.com/docs/api-class-names).
@@ -0,0 +1,13 @@
1
+ import { createStrictAPI } from '@compiled/react';
2
+
3
+ const { css, XCSSProp, cssMap, cx } = createStrictAPI<{
4
+ '&:hover': {
5
+ color: 'var(--ds-text-hover)';
6
+ background: 'var(--ds-surface-hover)' | 'var(--ds-surface-sunken-hover)';
7
+ };
8
+ color: 'var(--ds-text)';
9
+ background: 'var(--ds-surface)' | 'var(--ds-surface-sunken)';
10
+ bkgrnd: 'red' | 'green';
11
+ }>();
12
+
13
+ export { css, XCSSProp, cssMap, cx };
@@ -0,0 +1,312 @@
1
+ /** @jsxImportSource @compiled/react */
2
+ import { render } from '@testing-library/react';
3
+
4
+ import { css, cssMap, XCSSProp } from './__fixtures__/strict-api';
5
+
6
+ describe('createStrictAPI()', () => {
7
+ describe('css()', () => {
8
+ it('should type error when circumventing the excess property check', () => {
9
+ const styles = css({
10
+ color: 'var(--ds-text)',
11
+ accentColor: 'red',
12
+ // @ts-expect-error — Type 'string' is not assignable to type 'undefined'.ts(2322)
13
+ bkgrnd: 'red',
14
+ '&:hover': {
15
+ color: 'var(--ds-text-hover)',
16
+ // @ts-expect-error — Type 'string' is not assignable to type 'undefined'.ts(2322)
17
+ bkgrnd: 'red',
18
+ },
19
+ });
20
+
21
+ const { getByTestId } = render(<div css={styles} data-testid="div" />);
22
+
23
+ expect(getByTestId('div')).toHaveCompiledCss('color', 'var(--ds-text)');
24
+ });
25
+
26
+ it('should constrain declared types for css() func', () => {
27
+ // @ts-expect-error — Type '"red"' is not assignable to type '"var(--ds-surface)" | "var(--ds-surface-sunken" | undefined'.ts(2322)
28
+ const styles = css({ background: 'red' });
29
+
30
+ const { getByTestId } = render(<div css={styles} data-testid="div" />);
31
+
32
+ expect(getByTestId('div')).toHaveCompiledCss('background-color', 'red');
33
+ });
34
+
35
+ it('should mark all properties as optional', () => {
36
+ const styles1 = css({});
37
+ const styles2 = css({ '&:hover': {} });
38
+
39
+ const { getByTestId } = render(<div css={[styles1, styles2]} data-testid="div" />);
40
+
41
+ expect(getByTestId('div')).not.toHaveCompiledCss('color', 'red');
42
+ });
43
+
44
+ it('should constrain pseudos', () => {
45
+ const styles = css({
46
+ // @ts-expect-error — Type '"red"' is not assignable to type '"var(--ds-surface)" | "var(--ds-surface-sunken" | undefined'.ts(2322)
47
+ background: 'red',
48
+ '&:hover': {
49
+ // @ts-expect-error — Type '"red"' is not assignable to type '"var(--ds-surface)" | "var(--ds-surface-sunken" | undefined'.ts(2322)
50
+ background: 'red',
51
+ },
52
+ });
53
+
54
+ const { getByTestId } = render(<div css={styles} data-testid="div" />);
55
+
56
+ expect(getByTestId('div')).toHaveCompiledCss('background-color', 'red', { target: ':hover' });
57
+ });
58
+
59
+ it('should allow valid properties inside pseudos that are different to root', () => {
60
+ const styles = css({
61
+ background: 'var(--ds-surface)',
62
+ '&:hover': {
63
+ accentColor: 'red',
64
+ background: 'var(--ds-surface-hover)',
65
+ },
66
+ });
67
+
68
+ const { getByTestId } = render(<div css={styles} data-testid="div" />);
69
+
70
+ expect(getByTestId('div')).toHaveCompiledCss('background', 'var(--ds-surface-hover)', {
71
+ target: ':hover',
72
+ });
73
+ });
74
+
75
+ it('should allow valid properties', () => {
76
+ const styles = css({
77
+ background: 'var(--ds-surface)',
78
+ accentColor: 'red',
79
+ color: 'var(--ds-text)',
80
+ all: 'inherit',
81
+ '&:hover': { color: 'var(--ds-text-hover)' },
82
+ '&:invalid': { color: 'orange' },
83
+ });
84
+
85
+ const { getByTestId } = render(<div css={styles} data-testid="div" />);
86
+
87
+ expect(getByTestId('div')).toHaveCompiledCss('all', 'inherit');
88
+ });
89
+ });
90
+
91
+ describe('cssMap()', () => {
92
+ it('should allow valid properties', () => {
93
+ const styles = cssMap({
94
+ primary: {
95
+ background: 'var(--ds-surface)',
96
+ accentColor: 'red',
97
+ all: 'inherit',
98
+ '&:hover': { color: 'var(--ds-text-hover)' },
99
+ '&:invalid': { color: 'orange' },
100
+ },
101
+ });
102
+
103
+ const { getByTestId } = render(<div css={styles.primary} data-testid="div" />);
104
+
105
+ expect(getByTestId('div')).toHaveCompiledCss('background', 'var(--ds-surface)');
106
+ });
107
+
108
+ it('should allow valid properties inside pseudos that are different to root', () => {
109
+ const styles = cssMap({
110
+ primary: {
111
+ background: 'var(--ds-surface)',
112
+ '&:hover': {
113
+ accentColor: 'red',
114
+ background: 'var(--ds-surface-hover)',
115
+ },
116
+ },
117
+ });
118
+
119
+ const { getByTestId } = render(<div css={styles.primary} data-testid="div" />);
120
+
121
+ expect(getByTestId('div')).toHaveCompiledCss('background', 'var(--ds-surface-hover)', {
122
+ target: ':hover',
123
+ });
124
+ });
125
+
126
+ it('should type error invalid vales', () => {
127
+ const styles = cssMap({
128
+ primary: {
129
+ // @ts-expect-error — Type '{ val: string; }' is not assignable to type 'Readonly<Properties<string | number, string & {}>> & PseudosDeclarations & EnforceSchema<{ background: "var(--ds-surface)" | "var(--ds-surface-sunken"; }>'.
130
+ val: 'ok',
131
+ },
132
+ });
133
+
134
+ const { getByTestId } = render(<div css={styles.primary} data-testid="div" />);
135
+
136
+ expect(getByTestId('div')).toHaveCompiledCss('val', 'ok');
137
+ });
138
+
139
+ it('should type error invalid values in pseudos', () => {
140
+ const styles = cssMap({
141
+ primary: {
142
+ // @ts-expect-error — Type '"red"' is not assignable to type '"var(--ds-surface)" | "var(--ds-surface-sunken" | undefined'.ts(2322)
143
+ background: 'red',
144
+ '&:hover': {
145
+ // @ts-expect-error — Type 'string' is not assignable to type 'never'.ts(2322)
146
+ val: 'ok',
147
+ },
148
+ },
149
+ });
150
+
151
+ const { getByTestId } = render(<div css={styles.primary} data-testid="div" />);
152
+
153
+ expect(getByTestId('div')).toHaveCompiledCss('val', 'ok', { target: ':hover' });
154
+ });
155
+ });
156
+
157
+ describe('XCSSProp', () => {
158
+ it('should allow valid values', () => {
159
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'background', never>> }) {
160
+ return <button data-testid="button" className={xcss} />;
161
+ }
162
+
163
+ const { getByTestId } = render(<Button xcss={{ background: 'var(--ds-surface)' }} />);
164
+
165
+ expect(getByTestId('button')).toHaveCompiledCss('background', 'var(--ds-surface)');
166
+ });
167
+
168
+ it('should type error for invalid known values', () => {
169
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'background', never>> }) {
170
+ return <button data-testid="button" className={xcss} />;
171
+ }
172
+
173
+ const { getByTestId } = render(
174
+ <Button
175
+ xcss={{
176
+ // @ts-expect-error — Type '"red"' is not assignable to type '"var(--ds-surface)" | "var(--ds-surface-sunken" | CompiledPropertyDeclarationReference | undefined'.ts(2322)
177
+ background: 'red',
178
+ // @ts-expect-error — Type '{ background: string; }' is not assignable to type 'undefined'.ts(2322)
179
+ '&::after': {
180
+ background: 'red',
181
+ },
182
+ }}
183
+ />
184
+ );
185
+
186
+ expect(getByTestId('button')).toHaveCompiledCss('background-color', 'red');
187
+ });
188
+
189
+ it('should type error for invalid unknown values', () => {
190
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'background', never>> }) {
191
+ return <button data-testid="button" className={xcss} />;
192
+ }
193
+
194
+ const { getByTestId } = render(
195
+ <Button
196
+ xcss={{
197
+ // @ts-expect-error — Type '{ asd: number; }' is not assignable to type 'Internal$XCSSProp<"background", never, { background: "var(--ds-surface)" | "var(--ds-surface-sunken"; }, PickObjects<{ background: "var(--ds-surface)" | "var(--ds-surface-sunken"; }>, never>'.
198
+ asd: 0,
199
+ }}
200
+ />
201
+ );
202
+
203
+ expect(getByTestId('button')).toHaveCompiledCss('asd', '0');
204
+ });
205
+
206
+ it('should type error for unsupported known pseudos', () => {
207
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'background', never>> }) {
208
+ return <button data-testid="button" className={xcss} />;
209
+ }
210
+ const { getByTestId } = render(
211
+ <Button
212
+ xcss={{
213
+ // @ts-expect-error — Object literal may only specify known properties, and '':hover'' does not exist in type
214
+ ':hover': {
215
+ color: 'red',
216
+ },
217
+ }}
218
+ />
219
+ );
220
+
221
+ expect(getByTestId('button')).toHaveCompiledCss('color', 'red', { target: ':hover' });
222
+ });
223
+
224
+ it('should type error for unsupported unknown pseudos', () => {
225
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'background', never>> }) {
226
+ return <button data-testid="button" className={xcss} />;
227
+ }
228
+
229
+ const { getByTestId } = render(
230
+ <Button
231
+ xcss={{
232
+ // @ts-expect-error — Object literal may only specify known properties, and '':hover'' does not exist in type
233
+ ':asd': {
234
+ color: 'red',
235
+ },
236
+ }}
237
+ />
238
+ );
239
+
240
+ expect(getByTestId('button')).toHaveCompiledCss('color', 'red', { target: ':asd' });
241
+ });
242
+
243
+ it('should type error for invalid known values in pseudos', () => {
244
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'color', '&:hover'>> }) {
245
+ return <button data-testid="button" className={xcss} />;
246
+ }
247
+
248
+ const { getByTestId } = render(
249
+ <Button
250
+ xcss={{
251
+ '&:hover': {
252
+ // @ts-expect-error — Type '"red"' is not assignable to type 'CompiledPropertyDeclarationReference | "var(--ds-text)" | undefined'.ts(2322)
253
+ color: 'red',
254
+ },
255
+ }}
256
+ />
257
+ );
258
+
259
+ expect(getByTestId('button')).toHaveCompiledCss('color', 'red', { target: ':hover' });
260
+ });
261
+
262
+ it('should type error for invalid unknown values in pseudos', () => {
263
+ function Button({ xcss }: { xcss: ReturnType<typeof XCSSProp<'color', '&:hover'>> }) {
264
+ return <button data-testid="button" className={xcss} />;
265
+ }
266
+
267
+ const { getByTestId } = render(
268
+ <Button
269
+ xcss={{
270
+ '&:hover': {
271
+ // @ts-expect-error — Type '{ asd: string; }' is not assignable to type 'MarkAsRequired<XCSSItem<"color", { color: "var(--ds-text)"; }>, never>'.
272
+ asd: 'red',
273
+ },
274
+ }}
275
+ />
276
+ );
277
+
278
+ expect(getByTestId('button')).toHaveCompiledCss('asd', 'red', { target: ':hover' });
279
+ });
280
+
281
+ it('should enforce required properties', () => {
282
+ function Button({
283
+ xcss,
284
+ }: {
285
+ xcss: ReturnType<
286
+ typeof XCSSProp<
287
+ 'background',
288
+ never,
289
+ { requiredProperties: 'background'; requiredPseudos: never }
290
+ >
291
+ >;
292
+ }) {
293
+ return <button data-testid="button" className={xcss} />;
294
+ }
295
+
296
+ const { getByTestId } = render(
297
+ <Button
298
+ // @ts-expect-error — Type '{}' is not assignable to type 'Internal$XCSSProp<"background", never, EnforceSchema<{ background: "var(--ds-surface)" | "var(--ds-surface-sunken"; }>, object, { requiredProperties: "background"; requiredPseudos: never; }>'.ts(2322)
299
+ xcss={{}}
300
+ />
301
+ );
302
+
303
+ expect(getByTestId('button')).not.toHaveCompiledCss('color', 'red');
304
+ });
305
+ });
306
+
307
+ it('should throw when calling XCSSProp directly', () => {
308
+ expect(() => {
309
+ XCSSProp();
310
+ }).toThrow();
311
+ });
312
+ });
@@ -0,0 +1,21 @@
1
+ /** @jsxImportSource @compiled/react */
2
+ // eslint-disable-next-line import/no-extraneous-dependencies
3
+ import { css } from '@fixture/strict-api-test';
4
+ import { render } from '@testing-library/react';
5
+
6
+ describe('createStrictAPI()', () => {
7
+ describe('css()', () => {
8
+ it('should type error when circumventing the excess property check', () => {
9
+ const styles = css({
10
+ color: 'var(--ds-text)',
11
+ '&:hover': {
12
+ color: 'var(--ds-text-hover)',
13
+ },
14
+ });
15
+
16
+ const { getByTestId } = render(<div css={styles} data-testid="div" />);
17
+
18
+ expect(getByTestId('div')).toHaveCompiledCss('color', 'var(--ds-text)');
19
+ });
20
+ });
21
+ });
@@ -0,0 +1,223 @@
1
+ import type { StrictCSSProperties, CSSPseudos } from '../types';
2
+ import { createSetupError } from '../utils/error';
3
+ import { type CompiledStyles, cx, type Internal$XCSSProp } from '../xcss-prop';
4
+
5
+ type PseudosDeclarations = {
6
+ [Q in CSSPseudos]?: StrictCSSProperties;
7
+ };
8
+
9
+ type EnforceSchema<TObject> = {
10
+ [P in keyof TObject]?: P extends keyof CompiledSchema
11
+ ? TObject[P] extends Record<string, unknown>
12
+ ? EnforceSchema<TObject[P]>
13
+ : TObject[P]
14
+ : never;
15
+ };
16
+
17
+ type PickObjects<TObject> = {
18
+ [P in keyof TObject]: TObject[P] extends Record<string, unknown> ? TObject[P] : never;
19
+ };
20
+
21
+ interface CompiledAPI<TSchema> {
22
+ /**
23
+ * ## CSS
24
+ *
25
+ * Creates styles that are statically typed and useable with other Compiled APIs.
26
+ * For further details [read the documentation](https://compiledcssinjs.com/docs/api-css).
27
+ *
28
+ * @example
29
+ * ```
30
+ * const redText = css({
31
+ * color: 'red',
32
+ * });
33
+ *
34
+ * <div css={redText} />
35
+ * ```
36
+ */
37
+ css(
38
+ styles: StrictCSSProperties & PseudosDeclarations & EnforceSchema<TSchema>
39
+ ): StrictCSSProperties;
40
+ /**
41
+ * ## CSS Map
42
+ *
43
+ * Creates a collection of named styles that are statically typed and useable with other Compiled APIs.
44
+ * For further details [read the documentation](https://compiledcssinjs.com/docs/api-cssmap).
45
+ *
46
+ * @example
47
+ * ```
48
+ * const styles = cssMap({
49
+ * none: { borderStyle: 'none' },
50
+ * solid: { borderStyle: 'solid' },
51
+ * });
52
+ *
53
+ * <div css={styles.solid} />
54
+ * ```
55
+ */
56
+ cssMap<
57
+ TStyles extends Record<
58
+ string,
59
+ StrictCSSProperties & PseudosDeclarations & EnforceSchema<TSchema>
60
+ >
61
+ >(
62
+ styles: TStyles
63
+ ): {
64
+ readonly [P in keyof TStyles]: CompiledStyles<TStyles[P]>;
65
+ };
66
+ /**
67
+ * ## CX
68
+ *
69
+ * Use in conjunction with the {@link XCSSProp} to concatenate and conditionally apply
70
+ * declared styles. Can only be used with the {@link cssMap} and {@link XCSSProp} APIs.
71
+ *
72
+ * @example
73
+ * ```
74
+ * const styles = cssMap({
75
+ * text: { color: 'var(--ds-text)' },
76
+ * primary: { color: 'var(--ds-text-brand)' },
77
+ * });
78
+ *
79
+ * <Component xcss={cx(isPrimary && styles.text, !isPrimary && styles.primary)} />
80
+ * ```
81
+ */
82
+ cx: typeof cx;
83
+ /**
84
+ * ## XCSSProp
85
+ *
86
+ * Declare styles your component takes with all other styles marked as violations
87
+ * by the TypeScript compiler. There are two primary use cases for xcss prop:
88
+ *
89
+ * - safe style overrides
90
+ * - inverting style declarations
91
+ *
92
+ * Interverting style declarations is interesting for platform teams as
93
+ * it means products only pay for styles they use as they're now the ones who declare
94
+ * the styles!
95
+ *
96
+ * The {@link XCSSProp} type has generics two of which must be defined — use to explicitly
97
+ * set want you to maintain as API. Use {@link XCSSAllProperties} and {@link XCSSAllPseudos}
98
+ * to enable all properties and pseudos.
99
+ *
100
+ * The third generic is used to declare what properties and pseudos should be required.
101
+ *
102
+ * ```tsx
103
+ * interface MyComponentProps {
104
+ * // Color is accepted, all other properties / pseudos are considered violations.
105
+ * xcss?: ReturnType<typeof XCSSProp<'color', never>>;
106
+ *
107
+ * // Only backgrond color and hover pseudo is accepted.
108
+ * xcss?: ReturnType<typeof XCSSProp<'backgroundColor', '&:hover'>>;
109
+ *
110
+ * // All properties are accepted, all pseudos are considered violations.
111
+ * xcss?: ReturnType<typeof XCSSProp<XCSSAllProperties, never>>;
112
+ *
113
+ * // All properties are accepted, only the hover pseudo is accepted.
114
+ * xcss?: ReturnType<typeof XCSSProp<XCSSAllProperties, '&:hover'>>;
115
+ *
116
+ * // The xcss prop is required as well as the color property. No pseudos are required.
117
+ * xcss: ReturnType<
118
+ * typeof XCSSProp<
119
+ * XCSSAllProperties,
120
+ * '&:hover',
121
+ * { requiredProperties: 'color', requiredPseudos: never }
122
+ * >
123
+ * >;
124
+ * }
125
+ *
126
+ * function MyComponent({ xcss }: MyComponentProps) {
127
+ * return <div css={{ color: 'var(--ds-text-danger)' }} className={xcss} />
128
+ * }
129
+ * ```
130
+ *
131
+ * The xcss prop works with static inline objects and the [cssMap](https://compiledcssinjs.com/docs/api-cssmap) API.
132
+ *
133
+ * ```jsx
134
+ * // Declared as an inline object
135
+ * <Component xcss={{ color: 'var(--ds-text)' }} />
136
+ *
137
+ * // Declared with the cssMap API
138
+ * const styles = cssMap({ text: { color: 'var(--ds-text)' } });
139
+ * <Component xcss={styles.text} />
140
+ * ```
141
+ *
142
+ * To concatenate and conditonally apply styles use the {@link cssMap} and {@link cx} functions.
143
+ */
144
+ XCSSProp<
145
+ TAllowedProperties extends keyof StrictCSSProperties,
146
+ TAllowedPseudos extends CSSPseudos,
147
+ TRequiredProperties extends {
148
+ requiredProperties: TAllowedProperties;
149
+ requiredPseudos: TAllowedPseudos;
150
+ } = never
151
+ >(): Internal$XCSSProp<
152
+ TAllowedProperties,
153
+ TAllowedPseudos,
154
+ TSchema,
155
+ PickObjects<TSchema>,
156
+ TRequiredProperties
157
+ >;
158
+ }
159
+
160
+ type CompiledSchema = StrictCSSProperties & PseudosDeclarations;
161
+
162
+ /**
163
+ * ## Create Strict API
164
+ *
165
+ * Returns a strict subset of Compiled APIs augmented by a type definition.
166
+ * This API does not change Compileds build time behavior — merely augmenting
167
+ * the returned API types which enforce:
168
+ *
169
+ * - all APIs use object types
170
+ * - property values declared in the type definition must be used (else fallback to defaults)
171
+ * - a strict subset of pseudo states/selectors
172
+ * - unknown properties to be a type violation
173
+ *
174
+ * To set up:
175
+ *
176
+ * 1. Declare the API in a module (either local or in a package):
177
+ *
178
+ * @example
179
+ * ```tsx
180
+ * // ./foo.ts
181
+ * const { css } = createStrictAPI<{
182
+ * color: 'var(--ds-text)',
183
+ * '&:hover': { color: 'var(--ds-text-hover)' }
184
+ * }>();
185
+ *
186
+ * export { css };
187
+ * ```
188
+ *
189
+ * 2. Configure Compiled to pick up this module:
190
+ *
191
+ * @example
192
+ * ```diff
193
+ * // .compiledcssrc
194
+ * {
195
+ * + "importSources": ["./foo.ts"]
196
+ * }
197
+ * ```
198
+ *
199
+ * 3. Use the module in your application code:
200
+ *
201
+ * @example
202
+ * ```tsx
203
+ * import { css } from './foo';
204
+ *
205
+ * const styles = css({ color: 'var(--ds-text)' });
206
+ *
207
+ * <div css={styles} />
208
+ * ```
209
+ */
210
+ export function createStrictAPI<TSchema extends CompiledSchema>(): CompiledAPI<TSchema> {
211
+ return {
212
+ css() {
213
+ throw createSetupError();
214
+ },
215
+ cssMap() {
216
+ throw createSetupError();
217
+ },
218
+ cx,
219
+ XCSSProp() {
220
+ throw createSetupError();
221
+ },
222
+ };
223
+ }
package/src/css/index.ts CHANGED
@@ -6,7 +6,7 @@ import { createSetupError } from '../utils/error';
6
6
  /**
7
7
  * ## CSS
8
8
  *
9
- * Define styles that are statically typed and useable with other Compiled APIs.
9
+ * Create styles that are statically typed and useable with other Compiled APIs.
10
10
  * For further details [read the documentation](https://compiledcssinjs.com/docs/api-css).
11
11
  *
12
12
  * ### Style with objects