@compiled/react 0.16.0 → 0.16.1

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 (65) hide show
  1. package/dist/browser/css-map/index.d.ts +15 -26
  2. package/dist/browser/css-map/index.js +5 -4
  3. package/dist/browser/css-map/index.js.map +1 -1
  4. package/dist/browser/index.d.ts +1 -0
  5. package/dist/browser/index.js +1 -0
  6. package/dist/browser/index.js.map +1 -1
  7. package/dist/browser/jsx/jsx-local-namespace.d.ts +5 -1
  8. package/dist/browser/runtime/ac.d.ts +2 -2
  9. package/dist/browser/runtime/ac.js.map +1 -1
  10. package/dist/browser/runtime/ax.d.ts +1 -1
  11. package/dist/browser/runtime/ax.js.map +1 -1
  12. package/dist/browser/types.d.ts +9 -1
  13. package/dist/browser/xcss-prop/index.d.ts +130 -0
  14. package/dist/browser/xcss-prop/index.js +26 -0
  15. package/dist/browser/xcss-prop/index.js.map +1 -0
  16. package/dist/cjs/css-map/index.d.ts +15 -26
  17. package/dist/cjs/css-map/index.js +5 -4
  18. package/dist/cjs/css-map/index.js.map +1 -1
  19. package/dist/cjs/index.d.ts +1 -0
  20. package/dist/cjs/index.js +3 -1
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/jsx/jsx-local-namespace.d.ts +5 -1
  23. package/dist/cjs/runtime/ac.d.ts +2 -2
  24. package/dist/cjs/runtime/ac.js.map +1 -1
  25. package/dist/cjs/runtime/ax.d.ts +1 -1
  26. package/dist/cjs/runtime/ax.js.map +1 -1
  27. package/dist/cjs/types.d.ts +9 -1
  28. package/dist/cjs/xcss-prop/index.d.ts +130 -0
  29. package/dist/cjs/xcss-prop/index.js +30 -0
  30. package/dist/cjs/xcss-prop/index.js.map +1 -0
  31. package/dist/esm/css-map/index.d.ts +15 -26
  32. package/dist/esm/css-map/index.js +5 -4
  33. package/dist/esm/css-map/index.js.map +1 -1
  34. package/dist/esm/index.d.ts +1 -0
  35. package/dist/esm/index.js +1 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/jsx/jsx-local-namespace.d.ts +5 -1
  38. package/dist/esm/runtime/ac.d.ts +2 -2
  39. package/dist/esm/runtime/ac.js.map +1 -1
  40. package/dist/esm/runtime/ax.d.ts +1 -1
  41. package/dist/esm/runtime/ax.js.map +1 -1
  42. package/dist/esm/types.d.ts +9 -1
  43. package/dist/esm/xcss-prop/index.d.ts +130 -0
  44. package/dist/esm/xcss-prop/index.js +26 -0
  45. package/dist/esm/xcss-prop/index.js.map +1 -0
  46. package/package.json +2 -2
  47. package/src/css/__tests__/types.test.ts +1 -0
  48. package/src/css-map/index.ts +19 -33
  49. package/src/index.ts +1 -0
  50. package/src/jsx/jsx-local-namespace.ts +8 -1
  51. package/src/runtime/ac.ts +1 -1
  52. package/src/runtime/ax.ts +1 -1
  53. package/src/types.ts +68 -0
  54. package/src/xcss-prop/__tests__/xcss-prop.test.tsx +294 -0
  55. package/src/xcss-prop/index.ts +174 -0
  56. package/dist/browser/css-map/pseudos.d.ts +0 -1
  57. package/dist/browser/css-map/pseudos.js +0 -5
  58. package/dist/browser/css-map/pseudos.js.map +0 -1
  59. package/dist/cjs/css-map/pseudos.d.ts +0 -1
  60. package/dist/cjs/css-map/pseudos.js +0 -6
  61. package/dist/cjs/css-map/pseudos.js.map +0 -1
  62. package/dist/esm/css-map/pseudos.d.ts +0 -1
  63. package/dist/esm/css-map/pseudos.js +0 -5
  64. package/dist/esm/css-map/pseudos.js.map +0 -1
  65. package/src/css-map/pseudos.ts +0 -59
@@ -68,7 +68,14 @@ export namespace CompiledJSX {
68
68
  export type IntrinsicAttributes = ReactJSXIntrinsicAttributes;
69
69
  export type IntrinsicClassAttributes<T> = ReactJSXIntrinsicClassAttributes<T>;
70
70
  export type IntrinsicElements = {
71
- [K in keyof ReactJSXIntrinsicElements]: ReactJSXIntrinsicElements[K] & {
71
+ [K in keyof ReactJSXIntrinsicElements]: Omit<ReactJSXIntrinsicElements[K], 'className'> & {
72
+ // We override class name so we can pass xcss prop to it. We opt to do this instead of
73
+ // Making the output of cssMap() a string intersection so we can also have an inline object
74
+ // be declared.
75
+ /**
76
+ * The class name prop now can be given the output of xcss prop from `@compiled/react`.
77
+ */
78
+ className?: string | Record<string, any> | null | false;
72
79
  css?: CssFunction<void> | CssFunction<void>[];
73
80
  };
74
81
  };
package/src/runtime/ac.ts CHANGED
@@ -58,7 +58,7 @@ class AtomicGroups {
58
58
  * @param classes
59
59
  */
60
60
  export function ac(
61
- classNames: (AtomicGroups | string | undefined | false)[]
61
+ classNames: (AtomicGroups | string | null | undefined | false)[]
62
62
  ): AtomicGroups | undefined {
63
63
  // short circuit if there's no class names.
64
64
  if (classNames.length <= 1 && !classNames[0]) return undefined;
package/src/runtime/ax.ts CHANGED
@@ -27,7 +27,7 @@ const ATOMIC_GROUP_LENGTH = 5;
27
27
  *
28
28
  * @param classes
29
29
  */
30
- export default function ax(classNames: (string | undefined | false)[]): string | undefined {
30
+ export default function ax(classNames: (string | undefined | null | false)[]): string | undefined {
31
31
  if (classNames.length <= 1 && (!classNames[0] || classNames[0].indexOf(' ') === -1)) {
32
32
  // short circuit if there's no custom class names.
33
33
  return classNames[0] || undefined;
package/src/types.ts CHANGED
@@ -31,5 +31,73 @@ export type CssObject<TProps> = Readonly<{
31
31
  export type CssFunction<TProps = unknown> =
32
32
  | CssType<TProps>
33
33
  | BasicTemplateInterpolations // CSS values in tagged template expression
34
+ | null
34
35
  | boolean // Something like `false && styles`
35
36
  | undefined; // Something like `undefined && styles`
37
+
38
+ /*
39
+ * This list of pseudo-classes and pseudo-elements are from csstype
40
+ * but with & added to the front. Compiled supports both &-ful
41
+ * and &-less forms and both will target the current element
42
+ * (`&:hover` <==> `:hover`), however we force the use of the
43
+ * &-ful form for consistency with the nested spec for new APIs.
44
+ */
45
+ export type CSSPseudos =
46
+ | '&::after'
47
+ | '&::backdrop'
48
+ | '&::before'
49
+ | '&::cue'
50
+ | '&::cue-region'
51
+ | '&::first-letter'
52
+ | '&::first-line'
53
+ | '&::grammar-error'
54
+ | '&::marker'
55
+ | '&::placeholder'
56
+ | '&::selection'
57
+ | '&::spelling-error'
58
+ | '&::target-text'
59
+ | '&::view-transition'
60
+ | '&:active'
61
+ | '&:autofill'
62
+ | '&:blank'
63
+ | '&:checked'
64
+ | '&:default'
65
+ | '&:defined'
66
+ | '&:disabled'
67
+ | '&:empty'
68
+ | '&:enabled'
69
+ | '&:first'
70
+ | '&:focus'
71
+ | '&:focus-visible'
72
+ | '&:focus-within'
73
+ | '&:fullscreen'
74
+ | '&:hover'
75
+ | '&:in-range'
76
+ | '&:indeterminate'
77
+ | '&:invalid'
78
+ | '&:left'
79
+ | '&:link'
80
+ | '&:local-link'
81
+ | '&:optional'
82
+ | '&:out-of-range'
83
+ | '&:paused'
84
+ | '&:picture-in-picture'
85
+ | '&:placeholder-shown'
86
+ | '&:playing'
87
+ | '&:read-only'
88
+ | '&:read-write'
89
+ | '&:required'
90
+ | '&:right'
91
+ | '&:target'
92
+ | '&:user-invalid'
93
+ | '&:user-valid'
94
+ | '&:valid'
95
+ | '&:visited';
96
+
97
+ /**
98
+ * The xcss prop must be given all known available properties even
99
+ * if it takes a subset of them. This is ensure the (lack-of an)
100
+ * excess property check doesn't enable makers to circumvent the
101
+ * system and pass in values they shouldn't.
102
+ */
103
+ export type CSSProperties = Readonly<CSS.Properties<string | number>>;
@@ -0,0 +1,294 @@
1
+ /** @jsxImportSource @compiled/react */
2
+ // eslint-disable-next-line import/no-extraneous-dependencies
3
+ import { cssMap, cx } from '@compiled/react';
4
+ import { render } from '@testing-library/react';
5
+ import { expectTypeOf } from 'expect-type';
6
+
7
+ import type { XCSSProp, XCSSAllProperties, XCSSAllPseudos } from '../index';
8
+
9
+ describe('xcss prop', () => {
10
+ it('should allow all styles from xcss prop to class name when no constraints are applied', () => {
11
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<XCSSAllProperties, XCSSAllPseudos> }) {
12
+ return <div className={xcss}>foo</div>;
13
+ }
14
+
15
+ const styles = cssMap({
16
+ redColor: { color: 'red', '&::after': { backgroundColor: 'green' } },
17
+ });
18
+
19
+ const { getByText } = render(<CSSPropComponent xcss={styles.redColor} />);
20
+
21
+ expect(getByText('foo')).toHaveCompiledCss('color', 'red');
22
+ });
23
+
24
+ it('should type error when given a pseudo and none are allowed', () => {
25
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<XCSSAllProperties, never> }) {
26
+ return <div className={xcss}>foo</div>;
27
+ }
28
+
29
+ const styles = cssMap({
30
+ redColor: { color: 'red', '&::after': { backgroundColor: 'green' } },
31
+ });
32
+
33
+ const { getByText } = render(
34
+ <CSSPropComponent
35
+ // @ts-expect-error — Types of property '"&::after"' are incompatible.
36
+ xcss={styles.redColor}
37
+ />
38
+ );
39
+
40
+ expect(getByText('foo')).toHaveCompiledCss('color', 'red');
41
+ });
42
+
43
+ it('should concat styles from class name and xcss prop', () => {
44
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<XCSSAllProperties, XCSSAllPseudos> }) {
45
+ return (
46
+ <div css={{ color: 'blue' }} className={xcss}>
47
+ foo
48
+ </div>
49
+ );
50
+ }
51
+
52
+ const styles = cssMap({
53
+ redColor: { color: 'red' },
54
+ });
55
+
56
+ const { getByText } = render(<CSSPropComponent xcss={styles.redColor} />);
57
+
58
+ expect(getByText('foo')).toHaveCompiledCss('color', 'red');
59
+ });
60
+
61
+ it('should type error when passing styles that are not defined', () => {
62
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', XCSSAllPseudos> }) {
63
+ return <div className={xcss}>foo</div>;
64
+ }
65
+
66
+ const styles = cssMap({
67
+ redColor: { backgroundColor: 'red' },
68
+ });
69
+
70
+ expectTypeOf(
71
+ <CSSPropComponent
72
+ // @ts-expect-error — Types of property 'backgroundColor' are incompatible.
73
+ xcss={styles.redColor}
74
+ />
75
+ ).toBeObject();
76
+ });
77
+
78
+ it('should concat styles together', () => {
79
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<XCSSAllProperties, XCSSAllPseudos> }) {
80
+ return <div className={xcss}>foo</div>;
81
+ }
82
+ const styles = cssMap({
83
+ redColor: { color: 'red' },
84
+ greenBackground: { color: 'blue', backgroundColor: 'green' },
85
+ });
86
+
87
+ const { getByText } = render(
88
+ <CSSPropComponent xcss={cx(styles.redColor, styles.greenBackground)} />
89
+ );
90
+
91
+ expect(getByText('foo')).toHaveCompiledCss('color', 'blue');
92
+ expect(getByText('foo')).toHaveCompiledCss('backgroundColor', 'green');
93
+ });
94
+
95
+ it('should conditionally apply styles directly', () => {
96
+ const styles = cssMap({
97
+ redColor: { color: 'red' },
98
+ blueColor: { color: 'blue' },
99
+ });
100
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', never> }) {
101
+ return <div className={xcss}>foo</div>;
102
+ }
103
+ function Parent({ isRed }: { isRed: boolean }) {
104
+ return <CSSPropComponent xcss={isRed ? styles.redColor : styles.blueColor} />;
105
+ }
106
+
107
+ const { getByText, rerender } = render(<Parent isRed />);
108
+
109
+ expect(getByText('foo')).toHaveCompiledCss('color', 'red');
110
+ expect(getByText('foo')).not.toHaveCompiledCss('color', 'blue');
111
+
112
+ rerender(<Parent isRed={false} />);
113
+
114
+ expect(getByText('foo')).toHaveCompiledCss('color', 'blue');
115
+ expect(getByText('foo')).not.toHaveCompiledCss('color', 'red');
116
+ });
117
+
118
+ it('should conditionally apply styles via cx function', () => {
119
+ const styles = cssMap({
120
+ redColor: { color: 'red' },
121
+ blueColor: { color: 'blue' },
122
+ });
123
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', never> }) {
124
+ return <div className={xcss}>foo</div>;
125
+ }
126
+ function Parent({ isRed }: { isRed: boolean }) {
127
+ return <CSSPropComponent xcss={cx(isRed && styles.redColor, !isRed && styles.blueColor)} />;
128
+ }
129
+
130
+ const { getByText, rerender } = render(<Parent isRed />);
131
+
132
+ expect(getByText('foo')).toHaveCompiledCss('color', 'red');
133
+ expect(getByText('foo')).not.toHaveCompiledCss('color', 'blue');
134
+
135
+ rerender(<Parent isRed={false} />);
136
+
137
+ expect(getByText('foo')).toHaveCompiledCss('color', 'blue');
138
+ expect(getByText('foo')).not.toHaveCompiledCss('color', 'red');
139
+ });
140
+
141
+ it('should transform inline object', () => {
142
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', XCSSAllPseudos> }) {
143
+ return <div className={xcss}>foo</div>;
144
+ }
145
+
146
+ const { getByText } = render(<CSSPropComponent xcss={{ color: 'green' }} />);
147
+
148
+ expect(getByText('foo')).toHaveCompiledCss('color', 'green');
149
+ });
150
+
151
+ it('should type error when passing in a disallowed value in a pseudo mixed with allowed values', () => {
152
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', '&:hover'> }) {
153
+ return <div className={xcss}>foo</div>;
154
+ }
155
+
156
+ const styles = cssMap({
157
+ redColor: { color: 'red', '&:hover': { color: 'red', backgroundColor: 'red' } },
158
+ });
159
+
160
+ expectTypeOf(
161
+ <CSSPropComponent
162
+ // @ts-expect-error — Types of property 'backgroundColor' are incompatible.
163
+ xcss={styles.redColor}
164
+ />
165
+ ).toBeObject();
166
+ expectTypeOf(
167
+ <CSSPropComponent
168
+ xcss={{
169
+ color: 'red',
170
+ '&:hover': {
171
+ color: 'red',
172
+ // @ts-expect-error — Types of property 'backgroundColor' are incompatible.
173
+ backgroundColor: 'red',
174
+ },
175
+ }}
176
+ />
177
+ ).toBeObject();
178
+ });
179
+
180
+ it('should type error when passing in at rules to xcss prop', () => {
181
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', '&:hover'> }) {
182
+ return <div className={xcss}>foo</div>;
183
+ }
184
+
185
+ const styles = cssMap({
186
+ redColor: { color: 'red', '@media': { 'screen and': { color: 'red' } } },
187
+ });
188
+
189
+ expectTypeOf(
190
+ <CSSPropComponent
191
+ // @ts-expect-error — Types of property '"@media"' are incompatible.
192
+ xcss={styles.redColor}
193
+ />
194
+ ).toBeObject();
195
+ expectTypeOf(
196
+ <CSSPropComponent
197
+ xcss={{
198
+ color: 'red',
199
+ // @ts-expect-error — Type '{ screen: { color: string; backgroundColor: string; }; }' is not assignable to type 'undefined'.
200
+ '@media': {
201
+ screen: { color: 'red', backgroundColor: 'red' },
202
+ },
203
+ }}
204
+ />
205
+ ).toBeObject();
206
+ });
207
+
208
+ it('should block selectors api from CSS Map', () => {
209
+ function CSSPropComponent({ xcss }: { xcss: XCSSProp<'color', '&:hover'> }) {
210
+ return <div className={xcss}>foo</div>;
211
+ }
212
+
213
+ const styles = cssMap({
214
+ primary: {
215
+ selectors: { '&:not(:first-child):last-child': { color: 'red' } },
216
+ },
217
+ });
218
+
219
+ expectTypeOf(
220
+ <CSSPropComponent
221
+ // @ts-expect-error — Type 'CompiledStyles<{ '&:not(:first-child):last-child': { color: "red"; }; }>' is not assignable to type 'undefined'.
222
+ xcss={styles.primary}
223
+ />
224
+ ).toBeObject();
225
+ });
226
+
227
+ it('should mark a xcss prop as required', () => {
228
+ function CSSPropComponent({
229
+ xcss,
230
+ }: {
231
+ xcss: XCSSProp<
232
+ 'color' | 'backgroundColor',
233
+ '&:hover',
234
+ { requiredProperties: 'color'; requiredPseudos: never }
235
+ >;
236
+ }) {
237
+ return <div className={xcss}>foo</div>;
238
+ }
239
+
240
+ expectTypeOf(
241
+ <CSSPropComponent
242
+ // @ts-expect-error — Type '{}' is not assignable to type 'XCSSProp<"backgroundColor" | "color", "&:hover", { requiredProperties: "color"; }>'.
243
+ xcss={{}}
244
+ />
245
+ ).toBeObject();
246
+ });
247
+
248
+ it('should mark a xcss prop inside a pseudo as required', () => {
249
+ function CSSPropComponent({
250
+ xcss,
251
+ }: {
252
+ xcss: XCSSProp<
253
+ 'color' | 'backgroundColor',
254
+ '&:hover',
255
+ { requiredProperties: 'color'; requiredPseudos: never }
256
+ >;
257
+ }) {
258
+ return <div className={xcss}>foo</div>;
259
+ }
260
+
261
+ expectTypeOf(
262
+ <CSSPropComponent
263
+ xcss={{
264
+ color: 'red',
265
+ // @ts-expect-error — Property 'color' is missing in type '{}' but required in type '{ readonly color: string | number | CompiledPropertyDeclarationReference; }'.
266
+ '&:hover': {},
267
+ }}
268
+ />
269
+ ).toBeObject();
270
+ });
271
+
272
+ it('should mark a xcss prop pseudo as required', () => {
273
+ function CSSPropComponent({
274
+ xcss,
275
+ }: {
276
+ xcss: XCSSProp<
277
+ 'color' | 'backgroundColor',
278
+ '&:hover',
279
+ { requiredProperties: never; requiredPseudos: '&:hover' }
280
+ >;
281
+ }) {
282
+ return <div className={xcss}>foo</div>;
283
+ }
284
+
285
+ expectTypeOf(
286
+ <CSSPropComponent
287
+ // @ts-expect-error — Property '"&:hover"' is missing in type '{ color: string; }' but required in type '{ "&:hover": MarkAsRequired<XCSSItem<"backgroundColor" | "color">, never>; }'.
288
+ xcss={{
289
+ color: 'red',
290
+ }}
291
+ />
292
+ ).toBeObject();
293
+ });
294
+ });
@@ -0,0 +1,174 @@
1
+ import type * as CSS from 'csstype';
2
+
3
+ import { ac } from '../runtime';
4
+ import type { CSSPseudos, CSSProperties } from '../types';
5
+
6
+ type XCSSItem<TStyleDecl extends keyof CSSProperties> = {
7
+ [Q in keyof CSSProperties]: Q extends TStyleDecl
8
+ ? CompiledPropertyDeclarationReference | string | number
9
+ : never;
10
+ };
11
+
12
+ type XCSSPseudos<
13
+ TAllowedProperties extends keyof CSSProperties,
14
+ TAllowedPseudos extends CSSPseudos,
15
+ TRequiredProperties extends { requiredProperties: TAllowedProperties }
16
+ > = {
17
+ [Q in CSSPseudos]?: Q extends TAllowedPseudos
18
+ ? MarkAsRequired<XCSSItem<TAllowedProperties>, TRequiredProperties['requiredProperties']>
19
+ : never;
20
+ };
21
+
22
+ /**
23
+ * These APIs we don't want to allow to be passed through the `xcss` prop but we also
24
+ * must declare them so the (lack-of a) excess property check doesn't bite us and allow
25
+ * unexpected values through.
26
+ */
27
+ type BlockedRules = {
28
+ selectors?: never;
29
+ } & {
30
+ /**
31
+ * We currently block all at rules from xcss prop.
32
+ * This needs us to decide on what the final API is across Compiled to be able to set.
33
+ */
34
+ [Q in CSS.AtRules]?: never;
35
+ };
36
+
37
+ type CompiledPropertyDeclarationReference = {
38
+ ['__COMPILED_PROPERTY_DECLARATION_REFERENCE_DO_NOT_WRITE_DIRECTLY__']: true;
39
+ };
40
+
41
+ /**
42
+ * Used to mark styles that have been flushed through an API as being generated
43
+ * from Compiled. This is useful when you want other ends of the API to ensure they
44
+ * take Compiled generated styles and not some arbitrary object.
45
+ */
46
+ export type CompiledStyles<TObject> = {
47
+ [Q in keyof TObject]: TObject[Q] extends Record<string, unknown>
48
+ ? CompiledStyles<TObject[Q]>
49
+ : CompiledPropertyDeclarationReference;
50
+ };
51
+
52
+ /**
53
+ * Please think twice before using this type, you're better off declaring explicitly
54
+ * what your API should be, for example only defining `"color"`.
55
+ *
56
+ * Use in conjunction with {@link XCSSProp} to allow all properties to be given to
57
+ * your component.
58
+ */
59
+ export type XCSSAllProperties = keyof CSSProperties;
60
+
61
+ /**
62
+ * Please think twice before using this type, you're better off declaring explicitly
63
+ * what your API should be, for example not allowing any pseudos at all using the
64
+ * `never` type.
65
+ *
66
+ * Use in conjunction with {@link XCSSProp} to allow all pseudos to be given to
67
+ * your component.
68
+ */
69
+ export type XCSSAllPseudos = CSSPseudos;
70
+
71
+ /**
72
+ * ## xcss prop
73
+ *
74
+ * Declare styles your component takes with all other styles marked as violations
75
+ * by the TypeScript compiler. There are two primary use cases for xcss prop:
76
+ *
77
+ * - safe style overrides
78
+ * - inverting style declarations
79
+ *
80
+ * Interverting style declarations is interesting for platform teams as
81
+ * it means products only pay for styles they use as they're now the ones who declare
82
+ * the styles!
83
+ *
84
+ * The {@link XCSSProp} type has generics two of which must be defined — use to explicitly
85
+ * set want you to maintain as API. Use {@link XCSSAllProperties} and {@link XCSSAllPseudos}
86
+ * to enable all properties and pseudos.
87
+ *
88
+ * The third generic is used to declare what properties and pseudos should be required.
89
+ *
90
+ * @example
91
+ * ```
92
+ * interface MyComponentProps {
93
+ * // Color is accepted, all other properties / pseudos are considered violations.
94
+ * xcss?: XCSSProp<'color', never>;
95
+ *
96
+ * // Only backgrond color and hover pseudo is accepted.
97
+ * xcss?: XCSSProp<'backgroundColor', '&:hover'>;
98
+ *
99
+ * // All properties are accepted, all pseudos are considered violations.
100
+ * xcss?: XCSSProp<XCSSAllProperties, never>;
101
+ *
102
+ * // All properties are accepted, only the hover pseudo is accepted.
103
+ * xcss?: XCSSProp<XCSSAllProperties, '&:hover'>;
104
+ *
105
+ * // The xcss prop is required as well as the color property. No pseudos are required.
106
+ * xcss: XCSSProp<XCSSAllProperties, '&:hover', { requiredProperties: 'color', requiredPseudos: never }>;
107
+ * }
108
+ *
109
+ * function MyComponent({ xcss }: MyComponentProps) {
110
+ * return <div css={{ color: 'var(--ds-text-danger)' }} className={xcss} />
111
+ * }
112
+ * ```
113
+ *
114
+ * The xcss prop works with static inline objects and the [cssMap](https://compiledcssinjs.com/docs/api-cssmap) API.
115
+ *
116
+ * @example
117
+ * ```
118
+ * // Declared as an inline object
119
+ * <Component xcss={{ color: 'var(--ds-text)' }} />
120
+ *
121
+ * // Declared with the cssMap API
122
+ * const styles = cssMap({ text: { color: 'var(--ds-text)' } });
123
+ * <Component xcss={styles.text} />
124
+ * ```
125
+ *
126
+ * To concatenate and conditonally apply styles use the {@link cssMap} {@link cx} functions.
127
+ */
128
+ export type XCSSProp<
129
+ TAllowedProperties extends keyof CSSProperties,
130
+ TAllowedPseudos extends CSSPseudos,
131
+ TRequiredProperties extends {
132
+ requiredProperties: TAllowedProperties;
133
+ requiredPseudos: TAllowedPseudos;
134
+ } = never
135
+ > =
136
+ | (MarkAsRequired<XCSSItem<TAllowedProperties>, TRequiredProperties['requiredProperties']> &
137
+ MarkAsRequired<
138
+ XCSSPseudos<TAllowedProperties, TAllowedPseudos, TRequiredProperties>,
139
+ TRequiredProperties['requiredPseudos']
140
+ > &
141
+ BlockedRules)
142
+ | false
143
+ | null
144
+ | undefined;
145
+
146
+ type MarkAsRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
147
+
148
+ /**
149
+ * ## cx
150
+ *
151
+ * Use in conjunction with the {@link XCSSProp} to concatenate and conditionally apply
152
+ * declared styles. Can only be used with the `cssMap()` and {@link XCSSProp} APIs.
153
+ *
154
+ * @example
155
+ * ```
156
+ * const styles = cssMap({
157
+ * text: { color: 'var(--ds-text)' },
158
+ * primary: { color: 'var(--ds-text-brand)' },
159
+ * });
160
+ *
161
+ * <Component xcss={cx(isPrimary && styles.text, !isPrimary && styles.primary)} />
162
+ * ```
163
+ */
164
+ export const cx = <TStyles extends [...XCSSProp<any, any>[]]>(
165
+ ...styles: TStyles
166
+ ): TStyles[number] => {
167
+ // At runtime TStyles is resolved down to strings, but not at compile time.
168
+ // We circumvent the type system here because of that.
169
+ const actualStyles = styles as unknown as string[];
170
+
171
+ // The output should be a union type of passed in styles. This ensures the call
172
+ // site of xcss prop can raise violations when disallowed styles have been passed.
173
+ return ac(actualStyles) as TStyles[number];
174
+ };
@@ -1 +0,0 @@
1
- export type Pseudos = '&::after' | '&::backdrop' | '&::before' | '&::cue' | '&::cue-region' | '&::first-letter' | '&::first-line' | '&::grammar-error' | '&::marker' | '&::placeholder' | '&::selection' | '&::spelling-error' | '&::target-text' | '&::view-transition' | '&: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';
@@ -1,5 +0,0 @@
1
- // List of pseudo-classes and pseudo-elements are from csstype
2
- // but with & added in the front, so that we target the current element
3
- // (instead of a child element)
4
- export {};
5
- //# sourceMappingURL=pseudos.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pseudos.js","sourceRoot":"","sources":["../../../src/css-map/pseudos.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,uEAAuE;AACvE,+BAA+B"}
@@ -1 +0,0 @@
1
- export type Pseudos = '&::after' | '&::backdrop' | '&::before' | '&::cue' | '&::cue-region' | '&::first-letter' | '&::first-line' | '&::grammar-error' | '&::marker' | '&::placeholder' | '&::selection' | '&::spelling-error' | '&::target-text' | '&::view-transition' | '&: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';
@@ -1,6 +0,0 @@
1
- "use strict";
2
- // List of pseudo-classes and pseudo-elements are from csstype
3
- // but with & added in the front, so that we target the current element
4
- // (instead of a child element)
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- //# sourceMappingURL=pseudos.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pseudos.js","sourceRoot":"","sources":["../../../src/css-map/pseudos.ts"],"names":[],"mappings":";AAAA,8DAA8D;AAC9D,uEAAuE;AACvE,+BAA+B"}
@@ -1 +0,0 @@
1
- export type Pseudos = '&::after' | '&::backdrop' | '&::before' | '&::cue' | '&::cue-region' | '&::first-letter' | '&::first-line' | '&::grammar-error' | '&::marker' | '&::placeholder' | '&::selection' | '&::spelling-error' | '&::target-text' | '&::view-transition' | '&: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';
@@ -1,5 +0,0 @@
1
- // List of pseudo-classes and pseudo-elements are from csstype
2
- // but with & added in the front, so that we target the current element
3
- // (instead of a child element)
4
- export {};
5
- //# sourceMappingURL=pseudos.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pseudos.js","sourceRoot":"","sources":["../../../src/css-map/pseudos.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,uEAAuE;AACvE,+BAA+B"}