import type { StrictCSSProperties, CSSPseudos, CSSProps } from '../types.js';
import { createStrictSetupError } from '../utils/error.js';
import { type CompiledStyles, cx, type Internal$XCSSProp } from '../xcss-prop/index.js';
import type { AllowedStyles, ApplySchema, ApplySchemaMap, CompiledSchemaShape } from './types.js';
export interface StrictOptions {
media: string;
}
export interface CompiledAPI<
TSchema extends CompiledSchemaShape,
TAllowedMediaQueries extends string
> {
/**
* ## CSS
*
* Creates styles that are statically typed and useable with other Compiled APIs.
* For further details [read the documentation](https://compiledcssinjs.com/docs/api-css).
*
* This API does not currently work with XCSS prop.
*
* @example
* ```
* const redText = css({
* color: 'red',
* });
*
*
* ```
*/
css>(
styles: AllowedStyles & TStyles
// NOTE: This return type is deliberately not using ReadOnly>
// So it type errors when used with XCSS prop. When we update the compiler to work with
// it we can update the return type so it stops being a type violation.
): CSSProps;
/**
* ## CSS Map
*
* Creates a collection of named styles that are statically typed and useable with other Compiled APIs.
* For further details [read the documentation](https://compiledcssinjs.com/docs/api-cssmap).
*
* @example
* ```
* const styles = cssMap({
* none: { borderStyle: 'none' },
* solid: { borderStyle: 'solid' },
* });
*
*
* ```
*/
cssMap<
TObject extends Record>,
TStylesMap extends ApplySchemaMap
>(
styles: Record> & TStylesMap
): {
readonly [P in keyof TStylesMap]: CompiledStyles;
};
/**
* ## CX
*
* Use in conjunction with the {@link XCSSProp} to concatenate and conditionally apply
* declared styles. Can only be used with the {@link cssMap} and {@link XCSSProp} APIs.
*
* @example
* ```
* const styles = cssMap({
* text: { color: 'var(--ds-text)' },
* primary: { color: 'var(--ds-text-brand)' },
* });
*
*
* ```
*/
cx: typeof cx;
/**
* ## XCSSProp
*
* Declare styles your component takes with all other styles marked as violations
* by the TypeScript compiler. There are two primary use cases for xcss prop:
*
* - safe style overrides
* - inverting style declarations
*
* Interverting style declarations is interesting for platform teams as
* it means products only pay for styles they use as they're now the ones who declare
* the styles!
*
* The {@link XCSSProp} type has generics two of which must be defined — use to explicitly
* set want you to maintain as API. Use {@link XCSSAllProperties} and {@link XCSSAllPseudos}
* to enable all properties and pseudos.
*
* The third generic is used to declare what properties and pseudos should be required.
*
* ```tsx
* interface MyComponentProps {
* // Color is accepted, all other properties / pseudos are considered violations.
* xcss?: ReturnType>;
*
* // Only backgrond color and hover pseudo is accepted.
* xcss?: ReturnType>;
*
* // All properties are accepted, all pseudos are considered violations.
* xcss?: ReturnType>;
*
* // All properties are accepted, only the hover pseudo is accepted.
* xcss?: ReturnType>;
*
* // The xcss prop is required as well as the color property. No pseudos are required.
* xcss: ReturnType<
* typeof XCSSProp<
* XCSSAllProperties,
* '&:hover',
* { requiredProperties: 'color' }
* >
* >;
* }
*
* function MyComponent({ xcss }: MyComponentProps) {
* return
* }
* ```
*
* The xcss prop works with static inline objects and the [cssMap](https://compiledcssinjs.com/docs/api-cssmap) API.
*
* ```jsx
* // Declared as an inline object
*
*
* // Declared with the cssMap API
* const styles = cssMap({ text: { color: 'var(--ds-text)' } });
*
* ```
*
* To concatenate and conditonally apply styles use the {@link cssMap} and {@link cx} functions.
*/
XCSSProp<
TAllowedProperties extends keyof StrictCSSProperties,
TAllowedPseudos extends CSSPseudos,
TRequiredProperties extends {
requiredProperties: TAllowedProperties;
} = never
>(): Internal$XCSSProp<
TAllowedProperties,
TAllowedPseudos,
TAllowedMediaQueries,
TSchema,
TRequiredProperties,
'strict'
>;
}
/**
* ## Create Strict API
*
* Returns a strict subset of Compiled APIs augmented by a type definition.
* This API does not change Compileds build time behavior — merely augmenting
* the returned API types which enforce:
*
* - all APIs use object types
* - property values declared in the type definition must be used (else fallback to defaults)
* - a strict subset of pseudo states/selectors
* - unknown properties to be a type violation
*
* To set up:
*
* 1. Declare the API in a module (either local or in a package), optionally declaring accepted media queries.
*
* @example
* ```tsx
* // ./foo.ts
* interface Schema {
* color: 'var(--ds-text)',
* '&:hover': { color: 'var(--ds-text-hover)' }
* }
*
* const { css, cssMap, XCSSProp, cx } = createStrictAPI();
*
* export { css, cssMap, XCSSProp, cx };
* ```
*
* 2. Configure Compiled to pick up this module:
*
* @example
* ```diff
* // .compiledcssrc
* {
* + "importSources": ["./foo.ts"]
* }
* ```
*
* 3. Use the module in your application code:
*
* @example
* ```tsx
* import { css } from './foo';
*
* const styles = css({ color: 'var(--ds-text)' });
*
*
* ```
*/
export function createStrictAPI<
TSchema extends CompiledSchemaShape,
TCreateStrictAPIOptions extends StrictOptions = never
>(): CompiledAPI {
return {
css() {
throw createStrictSetupError();
},
cssMap() {
throw createStrictSetupError();
},
cx,
XCSSProp() {
throw createStrictSetupError();
},
};
}