next-yak
Version:
next-yak is a CSS-in-JS solution tailored for Next.js that seamlessly combines the expressive power of styled-components syntax with efficient build-time extraction of CSS using Next.js's built-in CSS configuration
144 lines (128 loc) • 4.88 kB
text/typescript
// This is the public facing API for the styled object.
import React from "react";
import type { YakTheme } from "./context/index.js";
import { CSSInterpolation, yakComponentSymbol } from "./cssLiteral.js";
/**
* Main styled interface that combines HTML tag mappings with the styled function.
* This is the primary entry point for creating styled components.
*/
export interface Styled extends MappedHtmlTags, StyledFn {}
/**
* Function interface for creating styled components from any component or HTML tag.
* Supports React components, HTML tags, and custom web components.
*/
export interface StyledFn {
<TProps extends object = React.DOMAttributes<Element> & React.RefAttributes<Element>>(
Component: HtmlTags | React.FunctionComponent<TProps> | CustomWebComponentTag,
): LiteralWithAttrs<TProps>;
}
/**
* A yak component with a special symbol that allows component targeting
* and proper attrs function handling.
* @example styled.svg`${Button}:hover & { fill: red; }` or styled(Button)`color: red;`
*/
export interface YakComponent<T> extends React.FunctionComponent<T> {
// This is intentionally typed to hide the internal implementation details.
[yakComponentSymbol]: [unknown, unknown, unknown];
}
/**
* Styled component with attrs method for adding default props.
* Extends StyledLiteral with the ability to specify default attributes.
*/
export interface LiteralWithAttrs<T extends object> extends StyledLiteral<T> {
attrs: <
TAttrsIn extends object = {},
TAttrsOut extends AttrsMerged<T, TAttrsIn> = AttrsMerged<T, TAttrsIn>,
>(
attrs: Attrs<T, TAttrsIn, TAttrsOut>,
) => StyledLiteral<Substitute<T, TAttrsIn>>;
}
/**
* Template literal function for defining CSS styles with interpolation support.
* Accepts CSS template strings and interpolated values with proper typing.
*/
export interface StyledLiteral<T> {
<TCSSProps>(
styles: TemplateStringsArray,
...values: Array<
CSSInterpolation<
T &
// Prevent TypeScript from inferring types from template literal usage
// This ensures proper typing and enables destructuring hints
NoInfer<TCSSProps> & { theme: YakTheme }
>
>
): YakComponent<TCSSProps & T>;
}
/**
* Function variant of attrs that receives current props and returns additional props.
* Allows for dynamic prop generation based on component state.
*/
export interface AttrsFunction<
TBaseProps,
TIn extends object = {},
TOut extends AttrsMerged<TBaseProps, TIn> = AttrsMerged<TBaseProps, TIn>,
> {
(p: Substitute<TBaseProps & { theme: YakTheme }, TIn>): Partial<TOut>;
}
/**
* Merges provided props with initial props, making specified props optional.
* Includes theme support for styled components.
*/
export type AttrsMerged<TBaseProps, TIn extends object = {}> = Substitute<
TBaseProps & { theme?: YakTheme },
TIn
>;
/**
* Maps all HTML tag names to their corresponding styled component types with attributes support.
* Provides typed access to all standard HTML elements through the styled interface.
*/
export type MappedHtmlTags = {
[Tag in HtmlTags]: LiteralWithAttrs<React.JSX.IntrinsicElements[Tag]>;
};
/**
* The attrs function allows adding additional props to a styled component.
* Props can be specified as an object or as a function that receives current props.
*/
export type Attrs<
TBaseProps,
TIn extends object = {},
TOut extends AttrsMerged<TBaseProps, TIn> = AttrsMerged<TBaseProps, TIn>,
> = Partial<TOut> | AttrsFunction<TBaseProps, TIn, TOut>;
/**
* Utility type to merge two object types, with properties from B taking precedence.
* If a property exists in both A and B, the property from B is used.
*/
export type Substitute<A extends object, B extends object> = FastOmit<A, keyof B> & B;
/**
* Union type of all valid HTML element tag names.
* Derived from React's JSX intrinsic elements.
*/
export type HtmlTags = keyof React.JSX.IntrinsicElements;
/**
* Custom web component tag pattern that must contain at least one hyphen.
* Follows the web component naming convention.
*/
export type CustomWebComponentTag = `${string}-${string}`;
/**
* Utility type to efficiently remove properties from an object type.
* More performant than the built-in Omit type for large object types.
*/
export type FastOmit<T extends object, U extends string | number | symbol> = {
[K in keyof T as K extends U ? never : K]: T[K];
};
/**
* Type of all functions that can be passed to manipulate styles
*/
export type RuntimeStyleProcessor<T> = (
props: T,
classNames: Set<string>,
style: React.CSSProperties,
) => void;
/**
* Utility type to keep the generic API of a component while still being able to use it in a selector
*/
export type GenericYakComponentOf<T, P = {}> = T &
YakComponent<P> & {
<G = {}>(props: P & G): React.ReactElement | null;
};