From a19d019bd418ebc3b9cba0e58f58b36ac2862a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 9 Dec 2024 06:50:27 +0100 Subject: [PATCH] Convert `@emotion/styled`'s source code to TypeScript (#3284) * Convert `@emotion/styled`'s source code to TypeScript * fixed entrypoint extension * fix types reference * add changeset * more localized cast * remove redundant cast * organize imports --- .changeset/metal-cups-allow.md | 5 + packages/serialize/src/index.ts | 6 +- packages/styled/base/package.json | 2 +- packages/styled/package.json | 21 +- packages/styled/src/base.d.ts | 2 - packages/styled/src/{base.js => base.tsx} | 98 +++++---- .../src/conditions/{false.js => false.ts} | 0 .../{is-browser.js => is-browser.ts} | 0 .../src/conditions/{true.js => true.ts} | 0 packages/styled/src/index.d.ts | 2 - packages/styled/src/index.js | 11 - packages/styled/src/index.ts | 42 ++++ .../jsx-namespace.ts} | 8 +- packages/styled/src/{tags.js => tags.ts} | 2 +- packages/styled/src/types.ts | 190 +++++++++++++++++ packages/styled/src/utils.js | 86 -------- packages/styled/src/utils.ts | 38 ++++ packages/styled/types/base.d.ts | 199 +----------------- packages/styled/types/index.d.ts | 33 +-- 19 files changed, 352 insertions(+), 393 deletions(-) create mode 100644 .changeset/metal-cups-allow.md delete mode 100644 packages/styled/src/base.d.ts rename packages/styled/src/{base.js => base.tsx} (72%) rename packages/styled/src/conditions/{false.js => false.ts} (100%) rename packages/styled/src/conditions/{is-browser.js => is-browser.ts} (100%) rename packages/styled/src/conditions/{true.js => true.ts} (100%) delete mode 100644 packages/styled/src/index.d.ts delete mode 100644 packages/styled/src/index.js create mode 100644 packages/styled/src/index.ts rename packages/styled/{types/jsx-namespace.d.ts => src/jsx-namespace.ts} (83%) rename packages/styled/src/{tags.js => tags.ts} (99%) create mode 100644 packages/styled/src/types.ts delete mode 100644 packages/styled/src/utils.js create mode 100644 packages/styled/src/utils.ts diff --git a/.changeset/metal-cups-allow.md b/.changeset/metal-cups-allow.md new file mode 100644 index 0000000000..63701932a4 --- /dev/null +++ b/.changeset/metal-cups-allow.md @@ -0,0 +1,5 @@ +--- +'@emotion/styled': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/packages/serialize/src/index.ts b/packages/serialize/src/index.ts index cdf6dee73e..57cfacf1c0 100644 --- a/packages/serialize/src/index.ts +++ b/packages/serialize/src/index.ts @@ -398,11 +398,11 @@ export function serializeStyles( strings as Interpolation ) } else { - const asTemplateStringsArr = strings as TemplateStringsArray - if (isDevelopment && asTemplateStringsArr[0] === undefined) { + const templateStringsArr = strings as TemplateStringsArray + if (isDevelopment && templateStringsArr[0] === undefined) { console.error(ILLEGAL_ESCAPE_SEQUENCE_ERROR) } - styles += asTemplateStringsArr[0] + styles += templateStringsArr[0] } // we start at 1 since we've already handled the first arg for (let i = 1; i < args.length; i++) { diff --git a/packages/styled/base/package.json b/packages/styled/base/package.json index bd1ec823ce..ce48434357 100644 --- a/packages/styled/base/package.json +++ b/packages/styled/base/package.json @@ -2,7 +2,7 @@ "main": "dist/emotion-styled-base.cjs.js", "module": "dist/emotion-styled-base.esm.js", "umd:main": "dist/emotion-styled-base.umd.min.js", - "types": "../types/base", + "types": "dist/emotion-styled-base.cjs.d.ts", "preconstruct": { "umdName": "emotionStyledBase" } diff --git a/packages/styled/package.json b/packages/styled/package.json index 0aa500762b..22d0e7a8cb 100644 --- a/packages/styled/package.json +++ b/packages/styled/package.json @@ -4,7 +4,7 @@ "description": "styled API for emotion", "main": "dist/emotion-styled.cjs.js", "module": "dist/emotion-styled.esm.js", - "types": "types/index.d.ts", + "types": "dist/emotion-styled.cjs.d.ts", "license": "MIT", "repository": "https://github.com/emotion-js/emotion/tree/main/packages/styled", "scripts": { @@ -40,7 +40,6 @@ "src", "dist", "base", - "types/*.d.ts", "macro.*" ], "umd:main": "dist/emotion-styled.umd.min.js", @@ -164,22 +163,22 @@ }, "imports": { "#is-development": { - "development": "./src/conditions/true.js", - "default": "./src/conditions/false.js" + "development": "./src/conditions/true.ts", + "default": "./src/conditions/false.ts" }, "#is-browser": { - "edge-light": "./src/conditions/false.js", - "workerd": "./src/conditions/false.js", - "worker": "./src/conditions/false.js", - "browser": "./src/conditions/true.js", - "default": "./src/conditions/is-browser.js" + "edge-light": "./src/conditions/false.ts", + "workerd": "./src/conditions/false.ts", + "worker": "./src/conditions/false.ts", + "browser": "./src/conditions/true.ts", + "default": "./src/conditions/is-browser.ts" } }, "preconstruct": { "umdName": "emotionStyled", "entrypoints": [ - "./index.js", - "./base.js" + "./index.ts", + "./base.tsx" ], "exports": { "extra": { diff --git a/packages/styled/src/base.d.ts b/packages/styled/src/base.d.ts deleted file mode 100644 index 6da8b18fdd..0000000000 --- a/packages/styled/src/base.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types/base' -export { default } from '../types/base' diff --git a/packages/styled/src/base.js b/packages/styled/src/base.tsx similarity index 72% rename from packages/styled/src/base.js rename to packages/styled/src/base.tsx index 35641c3916..66e49a725d 100644 --- a/packages/styled/src/base.js +++ b/packages/styled/src/base.tsx @@ -1,31 +1,40 @@ -import * as React from 'react' -import { - getDefaultShouldForwardProp, - composeShouldForwardProps - /* - type StyledOptions, - type CreateStyled, - type PrivateStyledComponent, - type StyledElementType - */ -} from './utils' -import { withEmotionCache, ThemeContext } from '@emotion/react' -import isDevelopment from '#is-development' import isBrowser from '#is-browser' +import isDevelopment from '#is-development' +import { Theme, ThemeContext, withEmotionCache } from '@emotion/react' +import { Interpolation, serializeStyles } from '@emotion/serialize' +import { useInsertionEffectAlwaysWithSyncFallback } from '@emotion/use-insertion-effect-with-fallbacks' import { + EmotionCache, getRegisteredStyles, insertStyles, - registerStyles + registerStyles, + SerializedStyles } from '@emotion/utils' -import { serializeStyles } from '@emotion/serialize' -import { useInsertionEffectAlwaysWithSyncFallback } from '@emotion/use-insertion-effect-with-fallbacks' +import * as React from 'react' +import { CreateStyled, ElementType, StyledOptions } from './types' +import { composeShouldForwardProps, getDefaultShouldForwardProp } from './utils' +export type { + ArrayInterpolation, + ComponentSelector, + CSSObject, + FunctionInterpolation, + Interpolation +} from '@emotion/serialize' const ILLEGAL_ESCAPE_SEQUENCE_ERROR = `You have illegal escape sequence in your template literal, most likely inside content's property value. Because you write your CSS inside a JavaScript string you actually have to do double escaping, so for example "content: '\\00d7';" should become "content: '\\\\00d7';". You can read more about this here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#ES2018_revision_of_illegal_escape_sequences` -const Insertion = ({ cache, serialized, isStringTag }) => { +const Insertion = ({ + cache, + serialized, + isStringTag +}: { + cache: EmotionCache + serialized: SerializedStyles + isStringTag: boolean +}) => { registerStyles(cache, serialized, isStringTag) const rules = useInsertionEffectAlwaysWithSyncFallback(() => @@ -52,10 +61,7 @@ const Insertion = ({ cache, serialized, isStringTag }) => { return null } -let createStyled /*: CreateStyled */ = ( - tag /*: any */, - options /* ?: StyledOptions */ -) => { +const createStyled = (tag: ElementType, options?: StyledOptions) => { if (isDevelopment) { if (tag === undefined) { throw new Error( @@ -66,8 +72,8 @@ let createStyled /*: CreateStyled */ = ( const isReal = tag.__emotion_real === tag const baseTag = (isReal && tag.__emotion_base) || tag - let identifierName - let targetClassName + let identifierName: string | undefined + let targetClassName: string | undefined if (options !== undefined) { identifierName = options.label targetClassName = options.target @@ -78,9 +84,11 @@ let createStyled /*: CreateStyled */ = ( shouldForwardProp || getDefaultShouldForwardProp(baseTag) const shouldUseAs = !defaultShouldForwardProp('as') - /* return function(): PrivateStyledComponent { */ return function () { - let args = arguments + // eslint-disable-next-line prefer-rest-params + let args = arguments as any as Array< + TemplateStringsArray | Interpolation + > let styles = isReal && tag.__emotion_styles !== undefined ? tag.__emotion_styles.slice(0) @@ -89,29 +97,35 @@ let createStyled /*: CreateStyled */ = ( if (identifierName !== undefined) { styles.push(`label:${identifierName};`) } - if (args[0] == null || args[0].raw === undefined) { + if ( + args[0] == null || + (args[0] as TemplateStringsArray).raw === undefined + ) { + // eslint-disable-next-line prefer-spread styles.push.apply(styles, args) } else { - if (isDevelopment && args[0][0] === undefined) { + const templateStringsArr = args[0] as TemplateStringsArray + if (isDevelopment && templateStringsArr[0] === undefined) { console.error(ILLEGAL_ESCAPE_SEQUENCE_ERROR) } - styles.push(args[0][0]) + styles.push(templateStringsArr[0]) let len = args.length let i = 1 for (; i < len; i++) { - if (isDevelopment && args[0][i] === undefined) { + if (isDevelopment && templateStringsArr[i] === undefined) { console.error(ILLEGAL_ESCAPE_SEQUENCE_ERROR) } - styles.push(args[i], args[0][i]) + styles.push(args[i], templateStringsArr[i]) } } - const Styled /*: PrivateStyledComponent */ = withEmotionCache( - (props, cache, ref) => { - const FinalTag = (shouldUseAs && props.as) || baseTag + const Styled: ElementType = withEmotionCache( + (props: Record, cache, ref) => { + const FinalTag = + (shouldUseAs && (props.as as React.ElementType)) || baseTag let className = '' - let classInterpolations = [] + let classInterpolations: Interpolation[] = [] let mergedProps = props if (props.theme == null) { mergedProps = {} @@ -146,7 +160,7 @@ let createStyled /*: CreateStyled */ = ( ? getDefaultShouldForwardProp(FinalTag) : defaultShouldForwardProp - let newProps = {} + let newProps: Record = {} for (let key in props) { if (shouldUseAs && key === 'as') continue @@ -196,20 +210,20 @@ let createStyled /*: CreateStyled */ = ( return `.${targetClassName}` } }) - - Styled.withComponent = ( - nextTag /*: StyledElementType */, - nextOptions /* ?: StyledOptions */ + ;(Styled as any).withComponent = ( + nextTag: ElementType, + nextOptions: StyledOptions ) => { - return createStyled(nextTag, { + const newStyled = createStyled(nextTag, { ...options, ...nextOptions, shouldForwardProp: composeShouldForwardProps(Styled, nextOptions, true) - })(...styles) + }) + return (newStyled as any)(...styles) } return Styled } } -export default createStyled +export default createStyled as CreateStyled diff --git a/packages/styled/src/conditions/false.js b/packages/styled/src/conditions/false.ts similarity index 100% rename from packages/styled/src/conditions/false.js rename to packages/styled/src/conditions/false.ts diff --git a/packages/styled/src/conditions/is-browser.js b/packages/styled/src/conditions/is-browser.ts similarity index 100% rename from packages/styled/src/conditions/is-browser.js rename to packages/styled/src/conditions/is-browser.ts diff --git a/packages/styled/src/conditions/true.js b/packages/styled/src/conditions/true.ts similarity index 100% rename from packages/styled/src/conditions/true.js rename to packages/styled/src/conditions/true.ts diff --git a/packages/styled/src/index.d.ts b/packages/styled/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/styled/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/styled/src/index.js b/packages/styled/src/index.js deleted file mode 100644 index dd11a7c906..0000000000 --- a/packages/styled/src/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import styled from './base' -import { tags } from './tags' - -// bind it to avoid mutating the original function -const newStyled = styled.bind() - -tags.forEach(tagName => { - newStyled[tagName] = newStyled(tagName) -}) - -export default newStyled diff --git a/packages/styled/src/index.ts b/packages/styled/src/index.ts new file mode 100644 index 0000000000..2d8877ff1a --- /dev/null +++ b/packages/styled/src/index.ts @@ -0,0 +1,42 @@ +import { Theme } from '@emotion/react' +import styled from './base' +import { ReactJSXIntrinsicElements } from './jsx-namespace' +import { tags } from './tags' +import { + CreateStyledComponent, + CreateStyled as BaseCreateStyled +} from './types' +export type { + ArrayInterpolation, + ComponentSelector, + CSSObject, + FunctionInterpolation, + Interpolation +} from '@emotion/serialize' +export type { + CreateStyledComponent, + FilteringStyledOptions, + StyledComponent, + StyledOptions +} from './types' + +export type StyledTags = { + [Tag in keyof ReactJSXIntrinsicElements]: CreateStyledComponent< + { + theme?: Theme + as?: React.ElementType + }, + ReactJSXIntrinsicElements[Tag] + > +} + +export interface CreateStyled extends BaseCreateStyled, StyledTags {} + +// bind it to avoid mutating the original function +const newStyled = styled.bind(null) as CreateStyled + +tags.forEach(tagName => { + ;(newStyled as any)[tagName] = newStyled(tagName as keyof typeof newStyled) +}) + +export default newStyled diff --git a/packages/styled/types/jsx-namespace.d.ts b/packages/styled/src/jsx-namespace.ts similarity index 83% rename from packages/styled/types/jsx-namespace.d.ts rename to packages/styled/src/jsx-namespace.ts index a45d7c3c21..612e28f115 100644 --- a/packages/styled/types/jsx-namespace.d.ts +++ b/packages/styled/src/jsx-namespace.ts @@ -7,8 +7,6 @@ type IsPreReact19 = 2 extends Parameters>['length'] ? true : false -export type ReactJSXIntrinsicElements = true extends IsPreReact19 - ? /** @ts-ignore */ - JSX.IntrinsicElements - : /** @ts-ignore */ - React.JSX.IntrinsicElements +// prettier-ignore +/** @ts-ignore */ +export type ReactJSXIntrinsicElements = true extends IsPreReact19 ? JSX.IntrinsicElements : React.JSX.IntrinsicElements diff --git a/packages/styled/src/tags.js b/packages/styled/src/tags.ts similarity index 99% rename from packages/styled/src/tags.js rename to packages/styled/src/tags.ts index 19bd402366..437bd1a03f 100644 --- a/packages/styled/src/tags.js +++ b/packages/styled/src/tags.ts @@ -135,4 +135,4 @@ export const tags = [ 'svg', 'text', 'tspan' -] +] as const diff --git a/packages/styled/src/types.ts b/packages/styled/src/types.ts new file mode 100644 index 0000000000..74ce3dcc81 --- /dev/null +++ b/packages/styled/src/types.ts @@ -0,0 +1,190 @@ +import { ComponentSelector, Interpolation } from '@emotion/serialize' +import { ReactJSXIntrinsicElements } from './jsx-namespace' +import { PropsOf, Theme } from '@emotion/react' + +/** Same as StyledOptions but shouldForwardProp must be a type guard */ +export interface FilteringStyledOptions< + Props = Record, + ForwardedProps extends keyof Props & string = keyof Props & string +> { + label?: string + shouldForwardProp?: (propName: string) => propName is ForwardedProps + target?: string +} + +export interface StyledOptions> { + label?: string + shouldForwardProp?: (propName: string) => boolean + target?: string +} + +/** + * @typeparam ComponentProps Props which will be included when withComponent is called + * @typeparam SpecificComponentProps Props which will *not* be included when withComponent is called + */ +export interface StyledComponent< + ComponentProps extends {}, + SpecificComponentProps extends {} = {}, + JSXProps extends {} = {} +> extends React.FC, + ComponentSelector { + withComponent>>( + component: C + ): StyledComponent< + ComponentProps & PropsOf, + {}, + { ref?: React.Ref> } + > + withComponent>>( + component: C + ): StyledComponent> + withComponent( + tag: Tag + ): StyledComponent +} + +/** + * @typeparam ComponentProps Props which will be included when withComponent is called + * @typeparam SpecificComponentProps Props which will *not* be included when withComponent is called + */ +export interface CreateStyledComponent< + ComponentProps extends {}, + SpecificComponentProps extends {} = {}, + JSXProps extends {} = {} +> { + ( + template: TemplateStringsArray, + ...styles: Array< + Interpolation + > + ): StyledComponent + + /** + * @typeparam AdditionalProps Additional props to add to your styled component + */ + ( + template: TemplateStringsArray, + ...styles: Array< + Interpolation< + ComponentProps & + SpecificComponentProps & + AdditionalProps & { theme: Theme } + > + > + ): StyledComponent< + ComponentProps & AdditionalProps, + SpecificComponentProps, + JSXProps + > + + /** + * @typeparam AdditionalProps Additional props to add to your styled component + */ + ( + ...styles: Array< + Interpolation< + ComponentProps & + SpecificComponentProps & + AdditionalProps & { theme: Theme } + > + > + ): StyledComponent< + ComponentProps & AdditionalProps, + SpecificComponentProps, + JSXProps + > +} + +/** + * @desc + * This function accepts a React component or tag ('div', 'a' etc). + * + * @example styled(MyComponent)({ width: 100 }) + * @example styled(MyComponent)(myComponentProps => ({ width: myComponentProps.width }) + * @example styled('div')({ width: 100 }) + * @example styled('div')(props => ({ width: props.width }) + */ +export interface CreateStyled { + < + C extends React.ComponentClass>, + ForwardedProps extends keyof React.ComponentProps & + string = keyof React.ComponentProps & string + >( + component: C, + options: FilteringStyledOptions, ForwardedProps> + ): CreateStyledComponent< + Pick, ForwardedProps> & { + theme?: Theme + }, + {}, + { + ref?: React.Ref> + } + > + + >>( + component: C, + options?: StyledOptions> + ): CreateStyledComponent< + PropsOf & { + theme?: Theme + }, + {}, + { + ref?: React.Ref> + } + > + + < + C extends React.ComponentType>, + ForwardedProps extends keyof React.ComponentProps & + string = keyof React.ComponentProps & string + >( + component: C, + options: FilteringStyledOptions, ForwardedProps> + ): CreateStyledComponent< + Pick, ForwardedProps> & { + theme?: Theme + } + > + + >>( + component: C, + options?: StyledOptions> + ): CreateStyledComponent< + PropsOf & { + theme?: Theme + } + > + + < + Tag extends keyof ReactJSXIntrinsicElements, + ForwardedProps extends keyof ReactJSXIntrinsicElements[Tag] & + string = keyof ReactJSXIntrinsicElements[Tag] & string + >( + tag: Tag, + options: FilteringStyledOptions< + ReactJSXIntrinsicElements[Tag], + ForwardedProps + > + ): CreateStyledComponent< + { theme?: Theme; as?: React.ElementType }, + Pick + > + + ( + tag: Tag, + options?: StyledOptions + ): CreateStyledComponent< + { theme?: Theme; as?: React.ElementType }, + ReactJSXIntrinsicElements[Tag] + > +} + +export type ElementType = React.ElementType & { + defaultProps?: Partial + __emotion_real?: ElementType + __emotion_base?: ElementType + __emotion_styles?: Interpolation[] + __emotion_forwardProp?: (propName: string) => boolean +} diff --git a/packages/styled/src/utils.js b/packages/styled/src/utils.js deleted file mode 100644 index 83a999d19a..0000000000 --- a/packages/styled/src/utils.js +++ /dev/null @@ -1,86 +0,0 @@ -/* import type { - ElementType, - StatelessFunctionalComponent, - AbstractComponent -} from 'react' */ -import isPropValid from '@emotion/is-prop-valid' - -/* -export type Interpolations = Array - -export type StyledElementType = - | string - | AbstractComponent<{ ...Props, className: string }, mixed> - -export type StyledOptions = { - label?: string, - shouldForwardProp?: string => boolean, - target?: string -} - -export type StyledComponent = StatelessFunctionalComponent & { - defaultProps: any, - toString: () => string, - withComponent: ( - nextTag: StyledElementType, - nextOptions?: StyledOptions - ) => StyledComponent -} - -export type PrivateStyledComponent = StyledComponent & { - __emotion_real: StyledComponent, - __emotion_base: any, - __emotion_styles: any, - __emotion_forwardProp: any -} -*/ - -const testOmitPropsOnStringTag = isPropValid -const testOmitPropsOnComponent = (key /*: string */) => key !== 'theme' - -export const getDefaultShouldForwardProp = (tag /*: ElementType */) => - typeof tag === 'string' && - // 96 is one less than the char code - // for "a" so this is checking that - // it's a lowercase character - tag.charCodeAt(0) > 96 - ? testOmitPropsOnStringTag - : testOmitPropsOnComponent - -export const composeShouldForwardProps = ( - tag /*: PrivateStyledComponent */, - options /*: StyledOptions | void */, - isReal /*: boolean */ -) => { - let shouldForwardProp - if (options) { - const optionsShouldForwardProp = options.shouldForwardProp - shouldForwardProp = - tag.__emotion_forwardProp && optionsShouldForwardProp - ? (propName /*: string */) => - tag.__emotion_forwardProp(propName) && - optionsShouldForwardProp(propName) - : optionsShouldForwardProp - } - - if (typeof shouldForwardProp !== 'function' && isReal) { - shouldForwardProp = tag.__emotion_forwardProp - } - - return shouldForwardProp -} - -/* -export type CreateStyledComponent = ( - ...args: Interpolations -) => StyledComponent - -export type CreateStyled = { - ( - tag: StyledElementType, - options?: StyledOptions - ): (...args: Interpolations) => StyledComponent, - [key: string]: CreateStyledComponent, - bind: () => CreateStyled -} -*/ diff --git a/packages/styled/src/utils.ts b/packages/styled/src/utils.ts new file mode 100644 index 0000000000..516b164e85 --- /dev/null +++ b/packages/styled/src/utils.ts @@ -0,0 +1,38 @@ +import * as React from 'react' +import isPropValid from '@emotion/is-prop-valid' +import { StyledOptions, ElementType } from './types' + +const testOmitPropsOnStringTag = isPropValid +const testOmitPropsOnComponent = (key: string) => key !== 'theme' + +export const getDefaultShouldForwardProp = (tag: React.ElementType) => + typeof tag === 'string' && + // 96 is one less than the char code + // for "a" so this is checking that + // it's a lowercase character + tag.charCodeAt(0) > 96 + ? testOmitPropsOnStringTag + : testOmitPropsOnComponent + +export const composeShouldForwardProps = ( + tag: ElementType, + options: StyledOptions | undefined, + isReal: boolean +) => { + let shouldForwardProp + if (options) { + const optionsShouldForwardProp = options.shouldForwardProp + shouldForwardProp = + tag.__emotion_forwardProp && optionsShouldForwardProp + ? (propName: string) => + tag.__emotion_forwardProp!(propName) && + optionsShouldForwardProp(propName) + : optionsShouldForwardProp + } + + if (typeof shouldForwardProp !== 'function' && isReal) { + shouldForwardProp = tag.__emotion_forwardProp + } + + return shouldForwardProp +} diff --git a/packages/styled/types/base.d.ts b/packages/styled/types/base.d.ts index c6533eec79..f8265bd861 100644 --- a/packages/styled/types/base.d.ts +++ b/packages/styled/types/base.d.ts @@ -1,197 +1,2 @@ -// Definitions by: Junyoung Clare Jang -// TypeScript Version: 3.2 - -import * as React from 'react' -import { ComponentSelector, Interpolation } from '@emotion/serialize' -import { PropsOf, Theme } from '@emotion/react' -import { ReactJSXIntrinsicElements } from './jsx-namespace' - -export { - ArrayInterpolation, - CSSObject, - FunctionInterpolation -} from '@emotion/serialize' - -export { ComponentSelector, Interpolation } - -/** Same as StyledOptions but shouldForwardProp must be a type guard */ -export interface FilteringStyledOptions< - Props = Record, - ForwardedProps extends keyof Props & string = keyof Props & string -> { - label?: string - shouldForwardProp?: (propName: string) => propName is ForwardedProps - target?: string -} - -export interface StyledOptions> { - label?: string - shouldForwardProp?: (propName: string) => boolean - target?: string -} - -/** - * @typeparam ComponentProps Props which will be included when withComponent is called - * @typeparam SpecificComponentProps Props which will *not* be included when withComponent is called - */ -export interface StyledComponent< - ComponentProps extends {}, - SpecificComponentProps extends {} = {}, - JSXProps extends {} = {} -> extends React.FC, - ComponentSelector { - withComponent>>( - component: C - ): StyledComponent< - ComponentProps & PropsOf, - {}, - { ref?: React.Ref> } - > - withComponent>>( - component: C - ): StyledComponent> - withComponent( - tag: Tag - ): StyledComponent -} - -/** - * @typeparam ComponentProps Props which will be included when withComponent is called - * @typeparam SpecificComponentProps Props which will *not* be included when withComponent is called - */ -export interface CreateStyledComponent< - ComponentProps extends {}, - SpecificComponentProps extends {} = {}, - JSXProps extends {} = {} -> { - ( - template: TemplateStringsArray, - ...styles: Array< - Interpolation - > - ): StyledComponent - - /** - * @typeparam AdditionalProps Additional props to add to your styled component - */ - ( - template: TemplateStringsArray, - ...styles: Array< - Interpolation< - ComponentProps & - SpecificComponentProps & - AdditionalProps & { theme: Theme } - > - > - ): StyledComponent< - ComponentProps & AdditionalProps, - SpecificComponentProps, - JSXProps - > - - /** - * @typeparam AdditionalProps Additional props to add to your styled component - */ - ( - ...styles: Array< - Interpolation< - ComponentProps & - SpecificComponentProps & - AdditionalProps & { theme: Theme } - > - > - ): StyledComponent< - ComponentProps & AdditionalProps, - SpecificComponentProps, - JSXProps - > -} - -/** - * @desc - * This function accepts a React component or tag ('div', 'a' etc). - * - * @example styled(MyComponent)({ width: 100 }) - * @example styled(MyComponent)(myComponentProps => ({ width: myComponentProps.width }) - * @example styled('div')({ width: 100 }) - * @example styled('div')(props => ({ width: props.width }) - */ -export interface CreateStyled { - < - C extends React.ComponentClass>, - ForwardedProps extends keyof React.ComponentProps & - string = keyof React.ComponentProps & string - >( - component: C, - options: FilteringStyledOptions, ForwardedProps> - ): CreateStyledComponent< - Pick, ForwardedProps> & { - theme?: Theme - }, - {}, - { - ref?: React.Ref> - } - > - - >>( - component: C, - options?: StyledOptions> - ): CreateStyledComponent< - PropsOf & { - theme?: Theme - }, - {}, - { - ref?: React.Ref> - } - > - - < - C extends React.ComponentType>, - ForwardedProps extends keyof React.ComponentProps & - string = keyof React.ComponentProps & string - >( - component: C, - options: FilteringStyledOptions, ForwardedProps> - ): CreateStyledComponent< - Pick, ForwardedProps> & { - theme?: Theme - } - > - - >>( - component: C, - options?: StyledOptions> - ): CreateStyledComponent< - PropsOf & { - theme?: Theme - } - > - - < - Tag extends keyof ReactJSXIntrinsicElements, - ForwardedProps extends keyof ReactJSXIntrinsicElements[Tag] & - string = keyof ReactJSXIntrinsicElements[Tag] & string - >( - tag: Tag, - options: FilteringStyledOptions< - ReactJSXIntrinsicElements[Tag], - ForwardedProps - > - ): CreateStyledComponent< - { theme?: Theme; as?: React.ElementType }, - Pick - > - - ( - tag: Tag, - options?: StyledOptions - ): CreateStyledComponent< - { theme?: Theme; as?: React.ElementType }, - ReactJSXIntrinsicElements[Tag] - > -} - -declare const styled: CreateStyled -export default styled +// TypeScript Version: 4.1 +export * from '../base' diff --git a/packages/styled/types/index.d.ts b/packages/styled/types/index.d.ts index 277e423f39..343fcf296e 100644 --- a/packages/styled/types/index.d.ts +++ b/packages/styled/types/index.d.ts @@ -1,33 +1,2 @@ -// Definitions by: Junyoung Clare Jang // TypeScript Version: 4.1 - -import { Theme } from '@emotion/react' -import { CreateStyled as BaseCreateStyled, CreateStyledComponent } from './base' -import { ReactJSXIntrinsicElements } from './jsx-namespace' - -export { - ArrayInterpolation, - ComponentSelector, - CSSObject, - FunctionInterpolation, - Interpolation, - StyledComponent, - StyledOptions, - FilteringStyledOptions, - CreateStyledComponent -} from './base' - -export type StyledTags = { - [Tag in keyof ReactJSXIntrinsicElements]: CreateStyledComponent< - { - theme?: Theme - as?: React.ElementType - }, - ReactJSXIntrinsicElements[Tag] - > -} - -export interface CreateStyled extends BaseCreateStyled, StyledTags {} - -declare const styled: CreateStyled -export default styled +export * from '..'