react-jss: add definitions

This commit is contained in:
Sebastian Silbermann
2018-08-22 19:10:48 +02:00
parent 3925a1622a
commit 2546493425
7 changed files with 288 additions and 0 deletions

26
types/react-jss/index.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
// Type definitions for react-jss 8.6
// Project: https://github.com/cssinjs/react-jss#readme
// Definitions by: Sebastian Silbermann <https://github.com/eps1lon>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import { createGenerateClassName, JSS, SheetsRegistry } from "jss";
import * as React from "react";
import { createTheming, ThemeProvider, withTheme } from "theming";
import injectSheet from "./lib/injectSheet";
import JssProvider, { Props as JssProviderProps } from "./lib/JssProvider";
// re-export types
export * from "./lib/injectSheet";
export { JssProviderProps };
// library implementations
export const jss: JSS;
export {
createGenerateClassName,
createTheming,
JssProvider,
SheetsRegistry,
ThemeProvider,
withTheme
};
export default injectSheet;

14
types/react-jss/lib/JssProvider.d.ts vendored Normal file
View File

@@ -0,0 +1,14 @@
import * as React from "react";
import { GenerateClassName, JSS, SheetsRegistry } from "jss";
export interface Props {
children: React.ReactNode;
classNamePrefix?: string;
disableStylesGeneration?: boolean;
jss?: JSS;
generateClassName?: GenerateClassName;
registry?: SheetsRegistry;
}
export default class JssProvider extends React.Component<Props> {}

116
types/react-jss/lib/injectSheet.d.ts vendored Normal file
View File

@@ -0,0 +1,116 @@
import * as CSS from "csstype";
import { CreateStyleSheetOptions, JSS } from "jss";
import * as React from "react";
import {
channel,
createTheming,
themeListener,
ThemeProvider,
withTheme
} from "theming";
/**
* omit from T every key K
*
* @internal
*/
export type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
/**
* `T extends ConsistentWith<T, U>` means that where `T` has overlapping properties with
* `U`, their value types do not conflict.
*
* @internal
*/
export type ConsistentWith<DecorationTargetProps, InjectedProps> = {
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
? InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: InjectedProps[P]
: DecorationTargetProps[P]
};
/**
* Like `T & U`, but using the value types from `U` where their properties overlap.
*
* @internal
*/
export type Overwrite<T, U> = Omit<T, keyof U> & U;
/**
* @internal
*/
export type PropsOf<C> = C extends new (props: infer P) => React.Component
? P
: C extends (props: infer P) => React.ReactElement<any> | null ? P : never;
/**
* a function that takes {component} and returns a component that passes along
* all the props to {component} except the {InjectedProps} and will accept
* additional {AdditionalProps}
*
* source mui-org/material-ui#12673
* @internal
*/
export type PropInjector<InjectedProps, AdditionalProps = {}> = <
C extends React.ComponentType<ConsistentWith<PropsOf<C>, InjectedProps>>
>(
component: C
) => React.ComponentType<
Omit<JSX.LibraryManagedAttributes<C, PropsOf<C>>, keyof InjectedProps> &
AdditionalProps
>;
export interface CSSProperties extends CSS.Properties<number | string> {
// Allow pseudo selectors and media queries
[k: string]:
| CSS.Properties<number | string>[keyof CSS.Properties]
| CSSProperties;
}
export type Styles<ClassKey extends string = string> = Record<
ClassKey,
CSSProperties
>;
export type StyleCreator<C extends string = string, T extends {} = {}> = (
theme: T
) => Styles<C>;
export interface Theming {
channel: string;
createTheming: typeof createTheming;
themeListener: typeof themeListener;
ThemeProvider: typeof ThemeProvider;
withTheme: typeof withTheme;
}
export interface InjectOptions extends CreateStyleSheetOptions {
jss?: JSS;
theming?: Theming;
}
export type ClassNameMap<C extends string> = Record<C, string>;
export type WithSheet<
S extends string | Styles | StyleCreator<string, any>,
GivenTheme = undefined
> = {
classes: ClassNameMap<
S extends string
? S
: S extends StyleCreator<infer C, any>
? C
: S extends Styles<infer C> ? C : never
>;
} & WithTheme<S extends StyleCreator<string, infer T> ? T : GivenTheme>;
export interface WithTheme<T> {
theme: T;
innerRef?: React.Ref<any> | React.RefObject<any>;
}
export interface StyledComponentProps<ClassKey extends string = string> {
classes?: Partial<ClassNameMap<ClassKey>>;
innerRef?: React.Ref<any> | React.RefObject<any>;
}
export default function injectSheet<C extends string, T extends object>(
stylesOrCreator: Styles<C> | StyleCreator<C, T>,
options?: InjectOptions
): PropInjector<WithSheet<C, T>, StyledComponentProps<C>>;

View File

@@ -0,0 +1,8 @@
{
"private": true,
"dependencies": {
"csstype": "^2.0.0",
"jss": "^9.5.0",
"theming": "^1.3.0"
}
}

View File

@@ -0,0 +1,97 @@
import * as React from "react";
import injectSheet, {
JssProvider,
SheetsRegistry,
Styles,
WithSheet,
ThemeProvider
} from "react-jss";
interface MyTheme {
color: {
primary: string;
secondary: string;
};
}
/**
* helper function to counter typescripts type widening
*/
function createStyles<C extends string>(styles: Styles<C>): Styles<C> {
return styles;
}
const styles = (theme: MyTheme) =>
createStyles({
myButton: {
color: theme.color.primary,
margin: 1,
"& span": {
fontWeight: "revert"
}
},
myLabel: {
fontStyle: "italic"
}
});
interface ButtonProps extends WithSheet<typeof styles> {
label: string;
}
const Button: React.SFC<ButtonProps> = ({ classes, children }) => {
return (
<button className={classes.myButton}>
<span className={classes.myLabel}>{children}</span>
</button>
);
};
const ManuallyStyles = () => {
return (
<Button
classes={{ myButton: "my-button", myLabel: "my-label" }}
label="Hello, World!"
theme={{ color: { primary: "red", secondary: "blue" } }}
/>
);
};
const StyledButton = injectSheet(styles)(Button);
const darkTheme: MyTheme = {
color: {
primary: "grey",
secondary: "brown"
}
};
const App = () => (
<ThemeProvider theme={darkTheme}>
<StyledButton label="I'm dark" />
</ThemeProvider>
);
function ssrRender(req: any, res: { send: (text: string) => any }) {
const mockedRenderToString = (e: React.ReactElement<any>) => `${e}`;
const sheets = new SheetsRegistry();
const body = mockedRenderToString(
<JssProvider classNamePrefix="dt-" registry={sheets}>
<StyledButton label="I come from the server" />
</JssProvider>
);
// Any instances of `injectSheet` within `<MyApp />` will have gotten sheets
// from `context` and added their Style Sheets to it by now.
return res.send(
mockedRenderToString(
<html>
<head>
<style type="text/css">{sheets.toString()}</style>
</head>
<body>{body}</body>
</html>
)
);
}

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"strictFunctionTypes": true
},
"files": [
"index.d.ts",
"lib/injectSheet.d.ts",
"lib/JssProvider.d.ts",
"react-jss-tests.tsx"
]
}

View File

@@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }