Skip to content

Commit

Permalink
Add preact typing
Browse files Browse the repository at this point in the history
  • Loading branch information
Ailrun committed May 26, 2018
1 parent 767108b commit 63c8c7b
Show file tree
Hide file tree
Showing 6 changed files with 314 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/preact-emotion/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
"description": "The Next Generation of CSS-in-JS, for Preact projects.",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
"types": "types/index.d.ts",
"files": [
"dist",
"src",
"macro.js"
"macro.js",
"types"
],
"scripts": {
"build": "npm-run-all clean rollup",
"clean": "rimraf dist",
"test:typescript": "dtslint types",
"watch": "rollup -c ../../rollup.config.js --watch",
"rollup": "rollup -c ../../rollup.config.js"
},
Expand Down
25 changes: 25 additions & 0 deletions packages/preact-emotion/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// TypeScript Version: 2.3
import {
Interpolation,
StyledOptions,
Themed,
} from 'create-emotion-styled/types/common';
import {
CreateStyled,
StyledComponent,
} from './preact';

export * from 'emotion';

export type ThemedReactEmotionInterface<Theme extends object> = CreateStyled<Theme>;

export {
CreateStyled,
Interpolation,
StyledComponent,
StyledOptions,
Themed,
};

declare const styled: CreateStyled;
export default styled;
78 changes: 78 additions & 0 deletions packages/preact-emotion/types/preact.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { ComponentConstructor, FunctionalComponent, Ref } from 'preact';
import { ClassInterpolation } from 'create-emotion';
import {
Interpolation,
StyledOptions,
StyledOtherProps,
StyledStatelessProps,
Themed,
} from 'create-emotion-styled/types/common';

export interface StyledComponentMethods<Props extends object, InnerProps extends object, Theme extends object> {
withComponent<T extends keyof JSX.IntrinsicElements>(
tag: T,
options?: StyledOptions,
): StyledOtherComponent<Props, JSX.IntrinsicElements[T], Theme>;

withComponent<IP extends object>(
component: FunctionalComponent<IP>,
options?: StyledOptions,
): StyledStatelessComponent<Props, IP, Theme>;

withComponent<IP extends object>(
component: ComponentConstructor<IP>,
options?: StyledOptions,
): StyledOtherComponent<Props, IP, Theme>;
}

export interface StyledStatelessComponent<Props extends object, InnerProps extends object, Theme extends object>
extends ComponentConstructor<StyledStatelessProps<Props & InnerProps, Theme>>,
ClassInterpolation,
StyledComponentMethods<Props, InnerProps, Theme> {}

export interface StyledOtherComponent<Props extends object, InnerProps extends object, Theme extends object>
extends ComponentConstructor<StyledOtherProps<Props & InnerProps, Theme, Ref<any>>>,
ClassInterpolation,
StyledComponentMethods<Props, InnerProps, Theme> {}

export type StyledComponent<Props extends object, InnerProps extends object, Theme extends object> =
| StyledStatelessComponent<Props, InnerProps, Theme>
| StyledOtherComponent<Props, InnerProps, Theme>
;

export interface CreateStyledStatelessComponent<InnerProps extends object, Theme extends object> {
<Props extends object, OverridedTheme extends object = Theme>(
...args: Array<Interpolation<Themed<Props, OverridedTheme>>>
): StyledStatelessComponent<Props, InnerProps, OverridedTheme>;
}

export interface CreateStyledOtherComponent<InnerProps extends object, Theme extends object> {
<Props extends object, OverridedTheme extends object = Theme>(
...args: Array<Interpolation<Themed<Props, OverridedTheme>>>
): StyledOtherComponent<Props, InnerProps, OverridedTheme>;
}

export interface CreateStyledFunction<Theme extends object> {
<T extends keyof JSX.IntrinsicElements>(
tag: T,
options?: StyledOptions,
): CreateStyledOtherComponent<JSX.IntrinsicElements[T], Theme>;

<IP extends object>(
component: FunctionalComponent<IP>,
options?: StyledOptions,
): CreateStyledStatelessComponent<IP, Theme>;

<IP extends object>(
component: ComponentConstructor<IP>,
options?: StyledOptions,
): CreateStyledOtherComponent<IP, Theme>;
}

export type CreateStyledShorthands<Theme extends object> = {
[T in keyof JSX.IntrinsicElements]: CreateStyledOtherComponent<JSX.IntrinsicElements[T], Theme>;
};

export interface CreateStyled<Theme extends object = any>
extends CreateStyledFunction<Theme>,
CreateStyledShorthands<Theme> {}
170 changes: 170 additions & 0 deletions packages/preact-emotion/types/test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
// tslint:disable-next-line:no-implicit-dependencies
import Preact, { h } from 'preact';
import styled, { flush, CreateStyled } from '../';

let Component;
let mount;

/*
* Inference HTML Tag Props
*/
const Component0 = styled.div({ color: 'red' });
mount = <Component0 onClick={(event: any) => event} />;

Component = styled('div')({ color: 'red' });
mount = <Component onClick={(event: any) => event} />;

Component = styled.div`color: red;`;
mount = <Component onClick={(event: any) => event} />;

Component = styled('div')`color: red;`;
mount = <Component onClick={(event: any) => event} />;

Component = styled.a({ color: 'red' });
mount = <Component href="#" />;

Component = styled('a')({ color: 'red' });
mount = <Component href="#" />;

/*
* Passing custom props
*/
interface CustomProps { lookColor: string; }

Component = styled.div<CustomProps>(
{ color: 'blue' },
props => ({
background: props.lookColor,
}),
props => ({
border: `1px solid ${props.lookColor}`,
}),
);
mount = <Component lookColor="red" />;

Component = styled('div')<CustomProps>(
{ color: 'blue' },
props => ({
background: props.lookColor,
}),
);
mount = <Component lookColor="red" />;

const anotherColor = 'blue';
Component = styled('div')`
background: ${(props: CustomProps) => props.lookColor};
color: ${anotherColor};
`;
mount = <Component lookColor="red" />;

/*
* With other components
*/
interface CustomProps2 { customProp: string; }
interface SFCComponentProps { className?: string; foo: string; }

const SFCComponent: Preact.FunctionalComponent<SFCComponentProps> = props => (
<div className={props.className}>{props.children} {props.foo}</div>
);

declare class MyClassC extends Preact.Component<CustomProps2> {
constructor(props: CustomProps2);
render(): JSX.Element;
}

// infer SFCComponentProps
Component = styled(SFCComponent)({ color: 'red' });
mount = <Component foo="bar" />;

// infer SFCComponentProps
Component = styled(SFCComponent)`color: red`;
mount = <Component foo="bar" />;

Component = styled(MyClassC)``;
mount = <Component customProp="abc" />;

// do not infer SFCComponentProps with pass CustomProps, need to pass both
Component = styled(SFCComponent)<CustomProps2>({
color: 'red',
}, props => ({
background: props.customProp,
}));
mount = <Component customProp="red" foo="bar" />;

// do not infer SFCComponentProps with pass CustomProps, need to pass both
Component = styled(SFCComponent)`
color: red;
background: ${(props: CustomProps2) => props.customProp};
`;
mount = <Component customProp="red" foo="bar" />;

/*
* With explicit theme
*/

interface Theme {
color: {
primary: string;
secondary: string;
};
}

const _styled = styled as CreateStyled<Theme>;

Component = _styled.div`
color: ${props => props.theme.color.primary}
`;
mount = <Component onClick={(event: any) => event} />;

/*
* withComponent
*/

interface CustomProps3 {
bgColor: string;
}

Component = styled.div<CustomProps3>(props => ({
bgColor: props.bgColor,
}));

const Link = Component.withComponent('a');
mount = <Link href="#" bgColor="red" />;

const Button = Component.withComponent('button');
mount = <Button type="submit" bgColor="red" />;

/*
* Can use emotion helpers importing from react-emotion
*/

flush();

/**
* innerRef
*/

Component = styled('div')``;
mount = <Component innerRef={(element: HTMLDivElement) => {}} />;

Component = styled.div``;
mount = <Component innerRef={(element: HTMLDivElement) => {}} />;

Component = styled.div({});
mount = <Component innerRef={(element: HTMLDivElement) => {}} />;

Component = Component.withComponent('input');
mount = <Component innerRef={(element: HTMLInputElement) => {}} />;

/*
* Reference to other styled component
*/
const Child = styled.div`
color: red;
`;

const Parent = styled.div`
${Child} {
color: blue;
}
`;
29 changes: 29 additions & 0 deletions packages/preact-emotion/types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"baseUrl": "../",
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"jsxFactory": "h",
"lib": [
"es6",
"dom"
],
"module": "commonjs",
"noEmit": true,
"noImplicitAny": true,
"noImplicitThis": true,
"strict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"target": "es5",
"typeRoots": [
"../"
],
"types": []
},
"include": [
"./*.ts",
"./*.tsx"
]
}
8 changes: 8 additions & 0 deletions packages/preact-emotion/types/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "dtslint/dtslint.json",
"rules": {
"array-type": [true, "generic"],
"callable-types": false,
"no-relative-import-in-test": false
}
}

0 comments on commit 63c8c7b

Please sign in to comment.