import type * as CSS from 'csstype';
import React from 'react';
import ComponentStyle from './models/ComponentStyle';
import { DefaultTheme } from './models/ThemeProvider';
import createWarnTooManyClasses from './utils/createWarnTooManyClasses';
import type { SupportedHTMLElements } from './utils/domElements';
export { CSS, DefaultTheme, SupportedHTMLElements };
export interface ExoticComponentWithDisplayName
extends React.ExoticComponent
{
defaultProps?: Partial
| undefined;
displayName?: string | undefined;
}
/**
* Use this type to disambiguate between a styled-component instance
* and a StyleFunction or any other type of function.
*/
export type StyledComponentBrand = {
readonly _sc: symbol;
};
export type BaseObject = {};
export type OmitNever = {
[K in keyof T as T[K] extends never ? never : K]: T[K];
};
export type FastOmit = {
[K in keyof T as K extends U ? never : K]: T[K];
};
export type Runtime = 'web' | 'native';
export type AnyComponent = ExoticComponentWithDisplayName
| React.ComponentType
;
export type KnownTarget = SupportedHTMLElements | AnyComponent;
export type WebTarget = (string & {}) | KnownTarget;
export type NativeTarget = AnyComponent;
export type StyledTarget = R extends 'web' ? WebTarget : NativeTarget;
export interface StyledOptions {
attrs?: Attrs[] | undefined;
componentId?: (R extends 'web' ? string : never) | undefined;
displayName?: string | undefined;
parentComponentId?: (R extends 'web' ? string : never) | undefined;
shouldForwardProp?: ShouldForwardProp | undefined;
}
export type Dict = {
[key: string]: T;
};
/**
* This type is intended for when data attributes are composed via
* the `.attrs` API:
*
* ```tsx
* styled.div.attrs({ 'data-testid': 'foo' })``
* ```
*
* Would love to figure out how to support this natively without having to
* manually compose the type, but haven't figured out a way to do so yet that
* doesn't cause specificity loss (see `test/types.tsx` if you attempt to embed
* `DataAttributes` directly in the `Attrs<>` type.)
*/
export type DataAttributes = {
[key: `data-${string}`]: any;
};
export type ExecutionProps = {
/**
* Dynamically adjust the rendered component or HTML tag, e.g.
* ```
* const StyledButton = styled.button``
*
*
* I'm an anchor now
*
* ```
*/
as?: KnownTarget | undefined;
forwardedAs?: KnownTarget | undefined;
theme?: DefaultTheme | undefined;
};
/**
* ExecutionProps but with `theme` narrowed from optional to required.
*
* Note: in RSC environments where ThemeProvider is a no-op,
* `theme` will be `undefined` at runtime.
*/
export interface ExecutionContext extends ExecutionProps {
theme: DefaultTheme;
}
export interface StyleFunction {
(executionContext: ExecutionContext & Props): Interpolation;
}
export type Interpolation = StyleFunction | StyledObject | TemplateStringsArray | string | number | false | undefined | null | Keyframes | StyledComponentBrand | RuleSet;
export type Attrs = (ExecutionProps & Partial) | ((props: ExecutionContext & Props) => ExecutionProps & Partial);
export type RuleSet = Interpolation[];
export type Styles = TemplateStringsArray | StyledObject | StyleFunction;
export type NameGenerator = (hash: number) => string;
export interface StyleSheet {
create: Function;
}
export interface Keyframes {
id: string;
name: string;
rules: string;
}
export interface Flattener {
(chunks: Interpolation[], executionContext: object | null | undefined, styleSheet: StyleSheet | null | undefined): Interpolation[];
}
export interface Stringifier {
(css: string, selector?: string | undefined, prefix?: string | undefined, componentId?: string | undefined): string[];
hash: string;
}
export interface ShouldForwardProp {
(prop: string, elementToBeCreated: StyledTarget): boolean;
}
export interface CommonStatics {
attrs: Attrs[];
target: StyledTarget;
shouldForwardProp?: ShouldForwardProp | undefined;
}
export interface IStyledStatics extends CommonStatics {
componentStyle: R extends 'web' ? ComponentStyle : never;
foldedComponentIds: R extends 'web' ? string : never;
inlineStyle: R extends 'native' ? InstanceType> : never;
target: StyledTarget;
styledComponentId: R extends 'web' ? string : never;
warnTooManyClasses?: (R extends 'web' ? ReturnType : never) | undefined;
}
/** ExecutionProps sans as/forwardedAs, pre-resolved so call sites relate against a concrete interface. */
interface ThemedExecutionProps {
theme?: DefaultTheme | undefined;
}
/**
* Props of a render target, for `as` / `forwardedAs`.
*
* One distributive conditional, never two nested, and tags resolve by indexed
* access rather than `React.ComponentPropsWithRef`. Both are load-bearing: this
* shape is the #5767 fix, and nesting a `T extends KnownTarget` check around it
* costs ~4x the check time. The `AnyComponent` arm doubles as that test, and
* every non-target falls through to `{}`.
*
* The `style` widening happens here, once per target, rather than at every JSX
* call site -- directly via {@link WithCSSVars} on the intrinsic arm, which
* needs no guard, and via {@link OverrideStyle} on the component arm, which
* does. See docs/type-performance.md before changing any of it.
*
* `R` carries the runtime so the widening stays web-only; it is deliberately
* undefaulted, since a default is what would let a native call site pick up web
* CSS by omission.
*/
export type TargetProps = T extends keyof React.JSX.IntrinsicElements ? IntrinsicProps : T extends AnyComponent ? ComponentTargetProps : {};
/**
* True when an application has augmented `React.HTMLAttributes` with a `data-*`
* template-literal index signature, the common pattern for allowing arbitrary
* data attributes. Detected by testing whether {@link DataAttributes}' key is
* already a key of a stock intrinsic element.
*
* Scope is exactly `data-${string}`: an `aria-${string}` or other custom-prefix
* template augmentation is not detected and still hits the {@link WithCSSVars}
* path (#5796). `data-*` is the dominant augmentation, so the narrow probe buys
* the common case; widening it means OR-ing another literal prefix in here.
*/
type IntrinsicElementsHaveDataIndex = keyof DataAttributes extends keyof React.JSX.IntrinsicElements['div'] ? true : false;
/**
* {@link WithCSSVars} for the augmented intrinsic path. Identical widening, but
* filters `style` with {@link FastOmit}'s mapped-type `as` clause instead of the
* built-in `Omit`. `Omit` is `Pick
>`,
* and distributing that `Exclude` over a template-literal key across every
* intrinsic element exceeds TypeScript's union complexity limit (#5796);
* `FastOmit` drops the key without the distribution.
*
* Kept off the normal path: `FastOmit` costs materially more instantiations at
* that scale, and the union `style` member (mirroring {@link WithCSSVars}) is
* what preserves the declaration-site relation a plain intersection regresses.
*/
type WithCSSVarsForDataIndex
= FastOmit
& {
style?: CSSPropertiesWithVars | (P[keyof P & 'style'] & {}) | undefined;
};
/**
* Props of an HTML or SVG tag.
*
* Both branches of {@link TargetProps} are named rather than inlined, so a
* component's type reads as `Substituted, { … }>`
* instead of the full expansion of every tag attribute. See {@link WithCSSVars}
* for why a conditional's inline branch cannot keep a name.
*
* Applies {@link WithCSSVars} directly except under a `data-*` augmentation,
* where {@link WithCSSVarsForDataIndex} avoids the `Omit` that would blow the
* union complexity limit. The probe is a global constant, so the common path is
* untouched.
*/
type IntrinsicProps = IntrinsicElementsHaveDataIndex extends true ? WithCSSVarsForDataIndex : WithCSSVars;
/**
* Props of a component render target. Named for the same reason as {@link IntrinsicProps}.
*
* The `style` widening is web-only: a React Native `style` takes a `ViewStyle`,
* which carries neither web CSS nor custom properties. This is the only seam that
* knows the runtime, which is why the gate sits here rather than inside
* {@link OverrideStyle}. The conditional is over `Runtime` -- two members, concrete
* at every entry point -- never over the target union.
*/
type ComponentTargetProps = R extends 'web' ? OverrideStyle> : React.ComponentPropsWithRef;
/**
* Used by PolymorphicComponent to define prop override cascading order.
*/
export type PolymorphicComponentProps | (BaseProps extends {
as?: infer A;
} ? A : never) | void, ForwardedAsTarget extends StyledTarget | void, AsTargetProps extends BaseObject = TargetProps, ForwardedAsTargetProps extends BaseObject = TargetProps> = NoInfer>, keyof ExecutionProps>> & ThemedExecutionProps & {
as?: AsTarget;
forwardedAs?: ForwardedAsTarget;
};
/**
* Resolves the call-site props for one usage of a polymorphic component from its
* `as` / `forwardedAs` targets. An `as` render target has its props merged over
* the base props and requires `as`; plain usage (or `as` being the wrapped
* component's own non-target type, e.g. Next.js Link's `as?: Url`) reaches
* {@link PolymorphicComponentProps} not at all, so the base props stay untouched
* and ref callbacks infer with spread props (#5687), the wrapped `as` stays
* assignable (#5734), and BaseProps keys keep completing (#5741). `forwardedAs`
* merges the same way, and loses to `as` where both name a target.
*
* The target test is `string | AnyComponent`, not `KnownTarget`: narrowing it
* drops custom element strings (`as="my-element"`) out of the target branch.
*
* Load-bearing shape, do not simplify: two conditionals with `unknown` sibling
* branches (not one three-way conditional), a leading flat `{ as?; forwardedAs? }`
* member, and positive `extends [string | AnyComponent]` discriminants. Collapsing
* the conditionals, dropping the flat member, or using a `[void]` discriminant
* each regress plain-call-site cost, `as`-target completion, or ref-callback
* inference (#5687) respectively.
*/
type PolymorphicCallProps | (BaseProps extends {
as?: infer A;
} ? A : never) | void, ForwardedAsTarget extends StyledTarget | void> = {
as?: AsTarget | undefined;
forwardedAs?: ForwardedAsTarget | undefined;
} & ([
AsTarget
] extends [string | AnyComponent] ? PolymorphicComponentProps & {
as: AsTarget;
} : unknown) & ([AsTarget] extends [string | AnyComponent] ? unknown : [ForwardedAsTarget] extends [string | AnyComponent] ? PolymorphicComponentProps & {
forwardedAs: ForwardedAsTarget;
} : NoInfer> & ThemedExecutionProps);
/**
* This type forms the signature for a forwardRef-enabled component
* that accepts the "as" prop to dynamically change the underlying
* rendered JSX. The interface will automatically attempt to extract
* props from the given rendering target to get proper typing for
* any specialized props in the target component.
*/
export interface PolymorphicComponent extends React.ForwardRefExoticComponent & {
as?: StyledTarget | undefined;
forwardedAs?: StyledTarget | undefined;
}> {
| (BaseProps extends {
as?: infer A;
} ? A : never) | void = void, ForwardedAsTarget extends StyledTarget | void = void>(props: PolymorphicCallProps): React.JSX.Element;
}
/**
* Some wrapped targets can't be statically introspected and their props
* collapse to `{}` -- most notably polymorphic-factory components (e.g. Mantine
* v7's `Button`, `Card`, `Menu.Item`), whose generic callable signature defeats
* `React.ComponentPropsWithRef`. A closed `{}` would reject every prop at the JSX
* call site, including `children`. Falling back to a permissive prop bag keeps
* these components usable; targets with introspectable props are unchanged.
*
* Applied only to the JSX call surface (`PolymorphicComponent`), never to the
* statics (`IStyledStatics`, `defaultProps`), so internal code keeps the real
* `Props` and the widening can't leak past the call site.
*
* The test distributes over `Props` first: `keyof` on a union intersects each
* member's keys, so a union of disjoint shapes has `keyof` of `never` while
* being perfectly introspectable. Checking each member alone avoids widening it.
*/
export type WidenUntypedProps = WidenForUntypedTarget;
/**
* Widens because the *target* is un-introspectable, even when the component
* declares props of its own.
*
* `Target` must be the target's props, never a bag the component's own props
* were merged into. Pass the latter and the test degrades: adding one transient
* prop makes `keyof` non-`never`, the widening switches off, and the target's
* own props including `children` start being rejected. That is #5756, and every
* call site here passes `TargetProps` for that reason.
*
* Applying it to an already-widened `Target` is a no-op, since the index
* signature makes `keyof` be `string`.
*/
export type WidenForUntypedTarget = (Target extends unknown ? (keyof Target extends never ? true : false) : never) extends true ? Props & {
[key: string]: unknown;
} : Props;
export interface IStyledComponentBase extends PolymorphicComponent>, IStyledStatics, StyledComponentBrand {
defaultProps?: (ExecutionProps & Partial) | undefined;
toString: () => string;
}
/**
* Intersected with `string` so styled components can be used as computed
* property keys in object styles: `{ [MyComponent]: { ... } }`.
* The conditional `R extends 'web' ? string : {}` was removed to avoid
* a type alias with a conditional - type aliases require full structural
* comparison on every use, while this unconditional intersection is cheaper.
*/
export type IStyledComponent = IStyledComponentBase & string;
export interface IStyledComponentFactory, in out OuterProps extends BaseObject, out OuterStatics extends BaseObject = BaseObject> {
(target: Target, options: StyledOptions, rules: RuleSet): IStyledComponent> & OuterStatics & Statics;
}
export interface IInlineStyleConstructor {
new (rules: RuleSet): IInlineStyle;
}
export interface IInlineStyle {
rules: RuleSet;
generateStyleObject(executionContext: ExecutionContext & Props): object;
}
export type CSSProperties = CSS.Properties;
/**
* The widened inline `style` prop: every CSS property plus CSS custom properties.
*
* The base is `React.CSSProperties`, not the library's {@link CSSProperties}
* (`CSS.Properties`), on purpose. The two are different
* csstype instantiations, and the `style` a consumer hand-writes in a declaration
* annotation (`IStyledComponentBase<'web', … & { style?: React.CSSProperties }>`)
* is React's. Sharing React's interface lets that assignability check take the
* intersection-member fast path (`React.CSSProperties & Vars` relates to
* `React.CSSProperties` without walking csstype) instead of relating two csstype
* instantiations member by member, once per component -- the declaration-site cost
* in docs/type-performance.md. Rebase only this cached base; do NOT also reshape
* {@link WithCSSVars}, which regresses instantiations (measured there). Object
* styles keep the richer numeric base via {@link CSSProperties}; only the inline
* `style` prop widens off React's.
*/
export type CSSPropertiesWithVars = React.CSSProperties & {
[key: `--${string}`]: string | number | undefined;
};
/**
* A `style` type that accepts exactly the fields given and nothing else.
*
* A declared `style` normally narrows the fields it names and leaves the rest of
* CSS available, which is what you want when constraining one or two properties:
*
* ```tsx
* // `width` must be a number; `color` and custom properties still work
* const Box = styled.div<{ style?: { width: number } }>``;
* ```
*
* Wrap the declaration in `CustomStyle` when the point is to forbid everything
* else, rather than writing `color?: never` for every property by hand:
*
* ```tsx
* // `width` is the only accepted style field
* const Box = styled.div<{ style?: CustomStyle<{ width: number }> }>``;
* ```
*/
export type CustomStyle = T & {
[K in Exclude]?: never;
};
/**
* Widens a target's `style` prop so CSS custom properties are accepted, and the
* taken branch of {@link OverrideStyle}. Keep it named: a conditional alias
* loses its name once it resolves, so an inline branch prints its whole
* expansion in every hover and error.
*
* `(P['style'] & {})` is load-bearing under `exactOptionalPropertyTypes` -- it
* filters `undefined` out so the `?:` stays the sole optional source -- and the
* explicit `| undefined` then restores `style={undefined}`.
*/
type WithCSSVars = Omit
& {
style?: CSSPropertiesWithVars | (P[keyof P & 'style'] & {}) | undefined;
};
/**
* Applies the `style` widening to a target that may or may not declare `style`.
*
* Applied once per target in {@link TargetProps}, never to a merged prop bag at
* a JSX call site. It runs before a component's own props, which then merge over
* it via {@link MergeProps} rather than replacing it.
*
* The test is `'style' extends keyof P`, not `P extends { style?: infer S }`:
* the latter is vacuously satisfied by `{}`, which would hand a `style` key to
* targets that expose no props at all and defeat `WidenUntypedProps` (#5756).
* Only {@link ComponentTargetProps} needs the guard; every intrinsic element
* declares `style`, so {@link IntrinsicProps} applies `WithCSSVars` directly.
*
* The outer `P extends unknown` is what makes this distribute over a union of
* prop shapes, and it is load-bearing (#5787). `keyof` a union is the keys
* *common* to every member, so an undistributed pass widens `A | B` against the
* shared keys alone and drops every member-specific prop -- a component typed
* `ButtonProps | AnchorProps` stops accepting `href`. Widening member by member
* keeps the union intact.
*
* `string extends keyof P` gates out a prop bag carrying a string index signature
* (`[k: string]: any`), returning it untouched. A generic polymorphic component
* (`(p: PropsWithChildren & ComponentProps)`)
* introspects at the `ElementType` constraint, where `ComponentProps`
* is `any`, so its extracted bag gains that index. {@link WithCSSVars}' `Omit`
* (`Pick>`) would then collapse every narrow named
* prop into the index -- `keyof P` is `string`, `Exclude` is
* still `string` -- widening a declared `variant: 'a' | 'b'` to `any` and letting
* `styled(Button)` accept props the component itself rejects (#5756). Declining to
* widen such a bag keeps the narrow props; the only thing given up is
* custom-property widening on a `style` that is already `any`, which is moot. A
* key-preserving `FastOmit` here would instead cost ~+11% instantiations (the
* homomorphic-mapped-type price the intrinsic path avoids); see
* docs/type-performance.md.
*/
type OverrideStyle = P extends unknown ? string extends keyof P ? P : 'style' extends keyof P ? WithCSSVars
: P : never;
export type CSSPseudos = {
[K in CSS.Pseudos]?: CSSObject;
};
export type CSSKeyframes = object & {
[key: string]: CSSObject;
};
export type CSSObject = StyledObject;
export interface StyledObject extends CSSProperties, CSSPseudos {
[key: string]: StyledObject | string | number | StyleFunction | RuleSet | undefined;
}
/**
* The `css` prop is not declared by default in the types as it would cause `css` to be present
* on the types of anything that uses styled-components indirectly, even if they do not use the
* babel plugin.
*
* To enable support for the `css` prop in TypeScript, create a `styled-components.d.ts` file in
* your project source with the following contents:
*
* ```ts
* import type { CSSProp } from "styled-components";
*
* declare module "react" {
* interface Attributes {
* css?: CSSProp;
* }
* }
* ```
*
* In order to get accurate typings for `props.theme` in `css` interpolations, see
* {@link DefaultTheme}.
*/
export type CSSProp = Interpolation;
export type { NoInfer } from './utils/noInfer';
/** The taken branch of {@link Substitute}. Named so it survives into hovers and
* error messages; see {@link WithCSSVars} for why an inline branch does not. */
export type Substituted = FastOmit & B;
export type Substitute = keyof B extends never ? {} extends B ? A : Substituted : Substituted;
/**
* A component's own props over its target's props, with `style` merged rather
* than replaced, so `styled.div<{ style?: { width: number } }>` constrains
* `width` and leaves the rest of CSS accepted. A field declared `never` is
* removed; {@link CustomStyle} removes everything a declaration omits.
*
* Under `exactOptionalPropertyTypes` the intersection leaves no `undefined` arm,
* so such a component rejects an explicit `style={undefined}`; declare
* `style?: X | undefined` to allow it. Omitting the prop is unaffected.
*
* Both conditional spellings of this were measured and rejected, one of them
* fatal. Keep it an intersection; see docs/type-performance.md before changing the shape.
*/
export type MergeProps = keyof B extends never ? {} extends B ? A : Merged : Merged;
/** The taken branch of {@link MergeProps}, named so hovers print a name rather
* than the expansion. Keep it named; see {@link Substituted}. */
export type Merged = FastOmit> & B;
/**
* Makes keys in K optional while keeping all others required.
* Used to make attrs-provided props optional on the final component.
*
* The guard is `[K] extends [never]`, not `keyof K extends never`. `K` is the set
* of attrs-provided keys and is `never` for any component without `.attrs()`,
* which is most of them, but `keyof never` is `string | number | symbol`, so the
* old spelling never short-circuited. Every such component paid an omit plus a
* `Partial>` that removed and re-added nothing, and carried both in its
* displayed type.
*
* The taken branch distributes over `P` with built-in `Omit`, not `FastOmit`.
* This mapped pass over the ~266-key widened intrinsic bag is the largest single
* cost of `.attrs` on a tag (measured ~30% of that kind's types); built-in `Omit`
* (Pick + Exclude) is more optimized than `FastOmit` here, the same result the
* `OverrideStyle` note records. The distribution is load-bearing: a bare
* `Omit` reads `keyof` as the union's *common* keys and collapses a
* union-props target (`styled(Pressable).attrs(...)` drops `href`), so the outer
* `P extends unknown` runs the omit per member and keeps the union intact. Do NOT
* spell it `FastOmit` (slower) or a bare undistributed `Omit` (unsound).
*/
export type MakeAttrsOptional = [K] extends [never] ? P : P extends unknown ? Omit
& Partial> : never;
export type InsertionTarget = HTMLElement | ShadowRoot;