From 71bb4d4a87c058cc9f9c7e73397df388453ae637 Mon Sep 17 00:00:00 2001 From: Rico Kahler Date: Sun, 19 Nov 2017 21:11:02 -0500 Subject: [PATCH 1/6] add typings for react-sketchapp --- types/react-sketchapp/index.d.ts | 288 ++++++++++++++++++ .../react-sketchapp/react-sketchapp-tests.tsx | 41 +++ types/react-sketchapp/tsconfig.json | 11 + types/react-sketchapp/tslint.json | 1 + 4 files changed, 341 insertions(+) create mode 100644 types/react-sketchapp/index.d.ts create mode 100644 types/react-sketchapp/react-sketchapp-tests.tsx create mode 100644 types/react-sketchapp/tsconfig.json create mode 100644 types/react-sketchapp/tslint.json diff --git a/types/react-sketchapp/index.d.ts b/types/react-sketchapp/index.d.ts new file mode 100644 index 0000000000..38573eac89 --- /dev/null +++ b/types/react-sketchapp/index.d.ts @@ -0,0 +1,288 @@ + +// Type definitions for react-sketchapp 0.12 +// Project: https://github.com/airbnb/react-sketchapp +// Definitions by: Rico Kahler +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +import * as React from "../react/index"; + +declare global { + export const context: SketchContext; +} + +// sketch interfaces taken from +// https://github.com/airbnb/react-sketchapp/blob/v0.12.1/src/types.js +export interface SketchPage { name: () => any } +export interface SketchAssetCollection { + colors: () => any[], + gradients: () => any[], +} +export interface SketchSharedStyleContainer { + setObjects: (objects: any[]) => void, + addSharedStyleWithName_firstInstance: (name: string, ins: any) => void, +} +export interface SketchDocumentData { + layerStyles: () => void, + layerTextStyles: () => SketchSharedStyleContainer, + layerSymbols: () => void, + assets: () => SketchAssetCollection, +} +export interface SketchDocument { + documentData: () => SketchDocumentData, + pages: () => SketchPage[], + addBlankPage: () => SketchPage, + currentPage: SketchPage, +} +export interface SketchContext { document: SketchDocument } + +/** + * Returns the top-level rendered Sketch object or an array of Sketch objects if you use + * components. + * @param element Top-level React component that defines your Sketch document. + * @param container The element to render into - will be replaced. Should either be a Sketch Group + * or Page Object. + * @return The top-most rendered native Sketch layer. + */ +export function render(element: JSX.Element, container?: any): any; + +/** + * Returns a Sketch JSON object for further consumption - doesn't add to the page. + * @param element + * @return The top-most Sketch layer as JSON. + */ +export function renderToJSON(element: JSX.Element): any; + +// https://github.com/airbnb/react-sketchapp/blob/v0.12.1/src/types.js#L59 +export type Color = string | number; + +/** + * The [`StyleSheet` api uses numbers as IDs][0] to pull registered styles. The component props + * can actually take either a `Style` or a `StyleReference` (where the `StyleReference` is given + * by a `StyleSheet` obj created with `StyleSheet.create`) + * [0]: https://github.com/airbnb/react-sketchapp/blob/v0.12.1/src/stylesheet/index.js#L34 + */ +export type StyleReference = number; + +/** + * Represents the base styles that can be applied to a component. + */ +export interface Style { + shadowColor?: Color, + shadowOffset?: { width?: number, height?: number }, + shadowOpacity?: number, + shadowRadius?: number, + width?: number, + height?: number, + top?: number, + left?: number, + right?: number, + bottom?: number, + minWidth?: number, + maxWidth?: number, + minHeight?: number, + maxHeight?: number, + margin?: number, + marginVertical?: number, + marginHorizontal?: number, + marginTop?: number, + marginBottom?: number, + marginLeft?: number, + marginRight?: number, + padding?: number, + paddingVertical?: number, + paddingHorizontal?: number, + paddingTop?: number, + paddingBottom?: number, + paddingLeft?: number, + paddingRight?: number, + borderWidth?: number, + borderTopWidth?: number, + borderRightWidth?: number, + borderBottomWidth?: number, + borderLeftWidth?: number, + position?: 'absolute' | 'relative', + flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse', + flexWrap?: 'wrap' | 'nowrap', + justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around', + alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch', + alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch', + overflow?: 'visible' | 'hidden' | 'scroll', + flex?: number, + flexGrow?: number, + flexShrink?: number, + flexBasis?: number, + aspectRatio?: number, + zIndex?: number, + backfaceVisibility?: 'visible' | 'hidden', + backgroundColor?: Color, + borderColor?: Color, + borderTopColor?: Color, + borderRightColor?: Color, + borderBottomColor?: Color, + borderLeftColor?: Color, + borderRadius?: number, + borderTopLeftRadius?: number, + borderTopRightRadius?: number, + borderBottomLeftRadius?: number, + borderBottomRightRadius?: number, + borderStyle?: 'solid' | 'dotted' | 'dashed', + opacity?: number, +} + +/** + * Represents all the Styles that can be applied to a `` component. The this interface + * extends the `Style` interface + */ +export interface TextStyle extends Style { + color?: Color, + fontFamily?: string, + fontSize?: number, + fontStyle?: 'normal' | 'italic', + fontWeight?: string, + textDecorationLine?: 'none' | 'underline' | 'double' | 'line-through', + textShadowOffset?: { width: number, height: number }, + textShadowRadius?: number, + textShadowColor?: Color, + letterSpacing?: number, + lineHeight?: number, + textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify', + writingDirection?: 'auto' | 'ltr' | 'rtl', +} + +// wanted to type these as classes because they are implemented as classes and typing them this +// way gives you typings like `Artboard.prototype` + + +// Artboard +export interface ArtboardProps { + /** + * The name to be displayed in the Sketch Layer List + */ + name?: string, + children?: any, + style?: Style | StyleReference, +} +/** + * Wrapper for Sketch's Artboards. + */ +export class Artboard extends React.Component { } + + +// Image +type ImageSource = string | { src: string }; +type ResizeMode = 'contain' | 'cover' | 'stretch' | 'center' | 'repeat' | 'none'; +interface ImageProps { + children?: any, + source?: ImageSource, + style?: Style | StyleReference, + resizeMode: ResizeMode, +} +export class Image extends React.Component { } + + +// RedBox +export interface RedBoxProps { + /** A JavaScript Error object */ + error: Error, +} +/** + * A red box / 'red screen of death' error handler. Thanks to [commissure/redbox-react.][0] + * --SUGGESTION: can you give a screenshot of what this looks like? + * + * [0]: https://github.com/commissure/redbox-react + */ +export class RedBox extends React.Component { } + + +// Text +export interface TextProps { + name?: string, + children?: string, + style?: TextStyle | StyleReference, +} +/** Text primitives */ +export class Text extends React.Component { } + + +// View +export interface ViewProps { + name?: string, + children?: any, + style?: Style | StyleReference, +} +/** View primitives */ +export class View extends React.Component { } + + +export const StyleSheet: { + hairlineWidth: 1, + absoluteFill: StyleReference, + /** + * Create an optimized `StyleSheet` reference from a style object. + */ + create: (t: T) => { + [P in keyof T]: StyleReference + }, + /** + * Flatten an array of style objects into one aggregated object, or look up the definition for a + * registered stylesheet. + */ + flatten: ( + input: (Style | TextStyle | StyleReference)[] | StyleReference | undefined | Style + ) => Style | TextStyle, // returns the expanded style or expanded style reference which conforms + // to the `Style | TextStyle` interface + /** + * resolve one style + */ + resolve: (style: Style | TextStyle) => { style: Style | TextStyle } +}; + +/** + * An interface to Sketch's shared text styles. Create styles with or without rendering them to + * the document canvas. + */ +export const TextStyles: { + /** + * The primary interface to TextStyles. Call this before rendering. + */ + create: ( + options: { context: SketchContext, clearExistingStyle?: boolean }, + styles: { [key: string]: TextStyle } + ) => any, + /** + * Find a stored native Sketch style object for a given JavaScript style object. You probably + * don't need to use this. + */ + resolve: (style: TextStyle) => any, + /** + * Find a stored style by name. + */ + get: (name: string) => TextStyle | undefined, + /** + * Find all of the registered styles. You probably don't need to use this. + */ + styles: { [key: string]: TextStyle | undefined }, + /** + * Reset the registered styles. + */ + clear: () => void, +}; + + +// Symbols +/** + * Returns a Sketch symbol given a node and an optional name. + * @param node The node object that will be rendered as a symbol + * @param name Optional name for the symbol, string can include backslashes to organize these + * symbols with Sketch. For example squares/blue + */ +export function makeSymbol

( + node: React.ComponentClass

| ((props: P) => JSX.Element), + name?: string +): React.ComponentClass

; + +/** + * Injects the symbols into Sketch's symbol page. **Call this before rendering.** + * @param context + */ +export function injectSymbols(context: SketchContext): void; \ No newline at end of file diff --git a/types/react-sketchapp/react-sketchapp-tests.tsx b/types/react-sketchapp/react-sketchapp-tests.tsx new file mode 100644 index 0000000000..e769df93b3 --- /dev/null +++ b/types/react-sketchapp/react-sketchapp-tests.tsx @@ -0,0 +1,41 @@ +import { Artboard, View, Text, StyleSheet, TextStyles, render, renderToJSON } from './index'; + +// the styles object should be a mapped typed mapping the keys of the object literal to numbers +const styles = StyleSheet.create({ + red: { + backgroundColor: '#FF00000' + }, + flexRow: { + flexDirection: 'row' + } +}); + +// style references are numbers +const styleReference = styles.red; + +const Document = () => + + text must be a string + + + + + +render(); +renderToJSON(); + +// Artboard is typed with a class so the prototype should be typed too (not very useful though) +Artboard.prototype.componentDidMount + +// context is a global but conflicts with others in this library +// TODO: currently this interface returns any but it looks like this method produces a side-affect +// and the return type isn't used anyway +TextStyles.create(context as any, { + normal: { + fontSize: 16, + }, + heading: { + fontSize: 16 * 1.618, + fontWeight: 'bold', + } +}); \ No newline at end of file diff --git a/types/react-sketchapp/tsconfig.json b/types/react-sketchapp/tsconfig.json new file mode 100644 index 0000000000..796c91f46b --- /dev/null +++ b/types/react-sketchapp/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2017", + "module": "es2015", + "jsx": "preserve", + "strict": true, + "typeRoots": [ + "../" + ] + } +} \ No newline at end of file diff --git a/types/react-sketchapp/tslint.json b/types/react-sketchapp/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/react-sketchapp/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" } From f14380642aac27f70b028887a6745209da8107fe Mon Sep 17 00:00:00 2001 From: Rico Kahler Date: Sun, 19 Nov 2017 21:31:17 -0500 Subject: [PATCH 2/6] run through linter --- types/react-sketchapp/index.d.ts | 241 +++++++++--------- .../react-sketchapp/react-sketchapp-tests.tsx | 8 +- types/react-sketchapp/tsconfig.json | 16 +- 3 files changed, 132 insertions(+), 133 deletions(-) diff --git a/types/react-sketchapp/index.d.ts b/types/react-sketchapp/index.d.ts index 38573eac89..055e5aadc3 100644 --- a/types/react-sketchapp/index.d.ts +++ b/types/react-sketchapp/index.d.ts @@ -1,39 +1,39 @@ - // Type definitions for react-sketchapp 0.12 // Project: https://github.com/airbnb/react-sketchapp // Definitions by: Rico Kahler // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.3 import * as React from "../react/index"; declare global { - export const context: SketchContext; + const context: SketchContext; } // sketch interfaces taken from // https://github.com/airbnb/react-sketchapp/blob/v0.12.1/src/types.js -export interface SketchPage { name: () => any } +export interface SketchPage { name: () => any; } export interface SketchAssetCollection { - colors: () => any[], - gradients: () => any[], + colors: () => any[]; + gradients: () => any[]; } export interface SketchSharedStyleContainer { - setObjects: (objects: any[]) => void, - addSharedStyleWithName_firstInstance: (name: string, ins: any) => void, + setObjects: (objects: any[]) => void; + addSharedStyleWithName_firstInstance: (name: string, ins: any) => void; } export interface SketchDocumentData { - layerStyles: () => void, - layerTextStyles: () => SketchSharedStyleContainer, - layerSymbols: () => void, - assets: () => SketchAssetCollection, + layerStyles: () => void; + layerTextStyles: () => SketchSharedStyleContainer; + layerSymbols: () => void; + assets: () => SketchAssetCollection; } export interface SketchDocument { - documentData: () => SketchDocumentData, - pages: () => SketchPage[], - addBlankPage: () => SketchPage, - currentPage: SketchPage, + documentData: () => SketchDocumentData; + pages: () => SketchPage[]; + addBlankPage: () => SketchPage; + currentPage: SketchPage; } -export interface SketchContext { document: SketchDocument } +export interface SketchContext { document: SketchDocument; } /** * Returns the top-level rendered Sketch object or an array of Sketch objects if you use @@ -47,7 +47,6 @@ export function render(element: JSX.Element, container?: any): any; /** * Returns a Sketch JSON object for further consumption - doesn't add to the page. - * @param element * @return The top-most Sketch layer as JSON. */ export function renderToJSON(element: JSX.Element): any; @@ -67,66 +66,66 @@ export type StyleReference = number; * Represents the base styles that can be applied to a component. */ export interface Style { - shadowColor?: Color, - shadowOffset?: { width?: number, height?: number }, - shadowOpacity?: number, - shadowRadius?: number, - width?: number, - height?: number, - top?: number, - left?: number, - right?: number, - bottom?: number, - minWidth?: number, - maxWidth?: number, - minHeight?: number, - maxHeight?: number, - margin?: number, - marginVertical?: number, - marginHorizontal?: number, - marginTop?: number, - marginBottom?: number, - marginLeft?: number, - marginRight?: number, - padding?: number, - paddingVertical?: number, - paddingHorizontal?: number, - paddingTop?: number, - paddingBottom?: number, - paddingLeft?: number, - paddingRight?: number, - borderWidth?: number, - borderTopWidth?: number, - borderRightWidth?: number, - borderBottomWidth?: number, - borderLeftWidth?: number, - position?: 'absolute' | 'relative', - flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse', - flexWrap?: 'wrap' | 'nowrap', - justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around', - alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch', - alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch', - overflow?: 'visible' | 'hidden' | 'scroll', - flex?: number, - flexGrow?: number, - flexShrink?: number, - flexBasis?: number, - aspectRatio?: number, - zIndex?: number, - backfaceVisibility?: 'visible' | 'hidden', - backgroundColor?: Color, - borderColor?: Color, - borderTopColor?: Color, - borderRightColor?: Color, - borderBottomColor?: Color, - borderLeftColor?: Color, - borderRadius?: number, - borderTopLeftRadius?: number, - borderTopRightRadius?: number, - borderBottomLeftRadius?: number, - borderBottomRightRadius?: number, - borderStyle?: 'solid' | 'dotted' | 'dashed', - opacity?: number, + shadowColor?: Color; + shadowOffset?: { width?: number, height?: number }; + shadowOpacity?: number; + shadowRadius?: number; + width?: number; + height?: number; + top?: number; + left?: number; + right?: number; + bottom?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + margin?: number; + marginVertical?: number; + marginHorizontal?: number; + marginTop?: number; + marginBottom?: number; + marginLeft?: number; + marginRight?: number; + padding?: number; + paddingVertical?: number; + paddingHorizontal?: number; + paddingTop?: number; + paddingBottom?: number; + paddingLeft?: number; + paddingRight?: number; + borderWidth?: number; + borderTopWidth?: number; + borderRightWidth?: number; + borderBottomWidth?: number; + borderLeftWidth?: number; + position?: 'absolute' | 'relative'; + flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse'; + flexWrap?: 'wrap' | 'nowrap'; + justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around'; + alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch'; + alignSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch'; + overflow?: 'visible' | 'hidden' | 'scroll'; + flex?: number; + flexGrow?: number; + flexShrink?: number; + flexBasis?: number; + aspectRatio?: number; + zIndex?: number; + backfaceVisibility?: 'visible' | 'hidden'; + backgroundColor?: Color; + borderColor?: Color; + borderTopColor?: Color; + borderRightColor?: Color; + borderBottomColor?: Color; + borderLeftColor?: Color; + borderRadius?: number; + borderTopLeftRadius?: number; + borderTopRightRadius?: number; + borderBottomLeftRadius?: number; + borderBottomRightRadius?: number; + borderStyle?: 'solid' | 'dotted' | 'dashed'; + opacity?: number; } /** @@ -134,101 +133,93 @@ export interface Style { * extends the `Style` interface */ export interface TextStyle extends Style { - color?: Color, - fontFamily?: string, - fontSize?: number, - fontStyle?: 'normal' | 'italic', - fontWeight?: string, - textDecorationLine?: 'none' | 'underline' | 'double' | 'line-through', - textShadowOffset?: { width: number, height: number }, - textShadowRadius?: number, - textShadowColor?: Color, - letterSpacing?: number, - lineHeight?: number, - textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify', - writingDirection?: 'auto' | 'ltr' | 'rtl', + color?: Color; + fontFamily?: string; + fontSize?: number; + fontStyle?: 'normal' | 'italic'; + fontWeight?: string; + textDecorationLine?: 'none' | 'underline' | 'double' | 'line-through'; + textShadowOffset?: { width: number, height: number }; + textShadowRadius?: number; + textShadowColor?: Color; + letterSpacing?: number; + lineHeight?: number; + textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify'; + writingDirection?: 'auto' | 'ltr' | 'rtl'; } // wanted to type these as classes because they are implemented as classes and typing them this // way gives you typings like `Artboard.prototype` - // Artboard export interface ArtboardProps { /** * The name to be displayed in the Sketch Layer List */ - name?: string, - children?: any, - style?: Style | StyleReference, + name?: string; + children?: any; + style?: Style | StyleReference; } /** * Wrapper for Sketch's Artboards. */ export class Artboard extends React.Component { } - // Image -type ImageSource = string | { src: string }; -type ResizeMode = 'contain' | 'cover' | 'stretch' | 'center' | 'repeat' | 'none'; -interface ImageProps { - children?: any, - source?: ImageSource, - style?: Style | StyleReference, - resizeMode: ResizeMode, +export type ImageSource = string | { src: string }; +export type ResizeMode = 'contain' | 'cover' | 'stretch' | 'center' | 'repeat' | 'none'; +export interface ImageProps { + children?: any; + source?: ImageSource; + style?: Style | StyleReference; + resizeMode: ResizeMode; } export class Image extends React.Component { } - // RedBox export interface RedBoxProps { /** A JavaScript Error object */ - error: Error, + error: Error; } /** - * A red box / 'red screen of death' error handler. Thanks to [commissure/redbox-react.][0] - * --SUGGESTION: can you give a screenshot of what this looks like? - * - * [0]: https://github.com/commissure/redbox-react + * A red box / 'red screen of death' error handler. Thanks to + * [commissure/redbox-react.](https://github.com/commissure/redbox-react) */ export class RedBox extends React.Component { } - // Text export interface TextProps { - name?: string, - children?: string, - style?: TextStyle | StyleReference, + name?: string; + children?: string; + style?: TextStyle | StyleReference; } /** Text primitives */ export class Text extends React.Component { } - // View export interface ViewProps { - name?: string, - children?: any, - style?: Style | StyleReference, + name?: string; + children?: any; + style?: Style | StyleReference; } /** View primitives */ export class View extends React.Component { } - export const StyleSheet: { - hairlineWidth: 1, - absoluteFill: StyleReference, + hairlineWidth: 1; + absoluteFill: StyleReference; /** * Create an optimized `StyleSheet` reference from a style object. */ create: (t: T) => { [P in keyof T]: StyleReference - }, - /** + }; + /** * Flatten an array of style objects into one aggregated object, or look up the definition for a * registered stylesheet. */ flatten: ( - input: (Style | TextStyle | StyleReference)[] | StyleReference | undefined | Style + input: Array