UNPKG

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
// 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; };