Skip to content

Commit

Permalink
fix(ts-typings): update TS type definitions (#1012)
Browse files Browse the repository at this point in the history
* fix(ts-typings): refactor 'h' annotations with jsx and support special attributes when using TSX

* test(definitions): add test for class attribute within TSX and 'h'

* refactor(ts-typings): restructure definitions  to separate files with only proper API exported

* test(definitions): add tests for all use cases with new typings. Also add Stateless components

* chore(ts-typings): apply ts formatter to all typings to prevent unconsistency

* fix(ts-typings): temporary fix anchor element issue caused by TS

* fix(ts-typings): properly support slot attributes on custom elements referenced via class
  • Loading branch information
Hotell committed Jan 18, 2017
1 parent f5ab707 commit 0c09adb
Show file tree
Hide file tree
Showing 7 changed files with 444 additions and 212 deletions.
130 changes: 19 additions & 111 deletions src/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,113 +1,21 @@
export { } from "./jsx";

// UMD library
export as namespace skate;

export type ComponentProps <El, T> = {
[P in keyof T]: PropOptions<El, T[P]>;
};

interface ComponentDefaultProps {
children?: JSX.Element[];
key?: string;
}

export class Component<Props> extends HTMLElement {
// Special hack for own components type checking.
// It works in combination with ElementAttributesProperty. It placed in jsx.d.ts.
// more detail, see: https://www.typescriptlang.org/docs/handbook/jsx.html
// and https://github.com/skatejs/skatejs/pull/952#issuecomment-264500153
_props: Props & ComponentDefaultProps;

static is: string;
static readonly props: ComponentProps<any, any>;
static readonly observedAttributes: string[];

// Custom Elements v1
connectedCallback(): void;
disconnectedCallback(): void;
attributeChangedCallback(name: string, oldValue: null | string, newValue: null | string): void;
adoptedCallback?(): void;

// SkateJS life cycle
updatedCallback(previousProps: { [nameOrSymbol: string]: any }): boolean | void;
renderCallback(): any;
renderedCallback(): void;

// SkateJS DEPRECATED
static created?(elem: Component<any>): void;
static attached?(elem: Component<any>): void;
static detached?(elem: Component<any>): void;
static attributeChanged?(elem: Component<any>, data: { name: string, oldValue: null | string, newValue: null | string }): void;
static updated(elem: Component<any>, prevProps: { [nameOrSymbol: string]: any }): boolean;
static render?(elem: Component<any>): any | undefined;
static rendered?(elem: Component<any>): void;
}

type AttributeReflectionBaseType = boolean | string;
type AttributeReflectionConfig = AttributeReflectionBaseType | {
source?: AttributeReflectionBaseType,
target?: AttributeReflectionBaseType
}
export interface PropOptions<El, T> {
attribute?: AttributeReflectionConfig ;
coerce?: (value: any) => T | null | undefined;
default?: T | null | undefined | ((elem: El, data: { name: string; }) => T | null | undefined);
deserialize?: (value: string | null) => T | null | undefined;
get?: <R>(elem: El, data: { name: string; internalValue: T; }) => R;
initial?: T | null | undefined | ((elem: El, data: { name: string; }) => T | null | undefined);
serialize?: (value: T | null | undefined) => string | null;
set?: (elem: El, data: { name: string; newValue: T | null | undefined; oldValue: T | null | undefined; }) => void;
}

export var define: {
(name: string, ctor: Function): any;
(ctor: Function): any;
};

export interface EmitOptions {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
detail?: any;
}
export function emit(elem: EventTarget, name: string, opts?: EmitOptions): void;

export var h: typeof vdom.element;

export function link(elem: Component<any>, target?: string): (e: Event) => void;

export var prop: {
create<T>(attr: PropOptions<any, T>): PropOptions<any, T> & ((attr: PropOptions<any, T>) => PropOptions<any, T>);

number(attr?: PropOptions<any, number>): PropOptions<any, number>;
boolean(attr?: PropOptions<any, boolean>): PropOptions<any, boolean>;
string(attr?: PropOptions<any, string>): PropOptions<any, string>;
array<T>(attr?: PropOptions<any, T[]>): PropOptions<any, T[]>;
object<T extends Object>(attr?: PropOptions<any, T>): PropOptions<any, T>;
};

export function props(elem: Component<any>, props?: any): void;

export function ready(elem: Component<any>, done: (c: Component<any>) => void): void;

// DEPRECATED
// export var symbols: any;

type VDOMElementTName = string | typeof Component | typeof vdom.element | { id: string; };
type VDOMElementChild = Function | string | number;
type VDOMElementSet = VDOMElementChild | VDOMElementChild[];

export var vdom: {
element(tname: VDOMElementTName, attrs: { key: any; statics: any; } & any, ...chren: VDOMElementSet[]): Component<any> | any;
element(tname: VDOMElementTName, ...chren: VDOMElementSet[]): Component<any> | any;
builder(): typeof vdom.element;
builder(...tags: string[]): (typeof vdom.element)[];

attr(...args: any[]): void;
elementClose: Function;
elementOpen: Function;
elementOpenEnd: Function;
elementOpenStart: Function;
elementVoid: Function;
text: Function;
};
// empty reexport so user get's JSX to global
export { } from './ts-typings/jsx';

// Public API
export {
Component,
ComponentProps,
StatelessComponent,
SFC,
prop,
props,
ready,
link,
define,
emit,
h,
vdom
} from './ts-typings/api';
138 changes: 138 additions & 0 deletions src/ts-typings/api.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { Key, HTMLProps } from './common';

export type ComponentProps<El, T> = {
[P in keyof T]: PropOptions<El, T[P]>;
};

interface ComponentDefaultProps {
children?: VDOMElement<any>[];
key?: Key;
}

export interface StatelessComponent<Props> {
(props: Props, children?: VDOMNode): VDOMElement<any>,
}
export type SFC<P> = StatelessComponent<P>;

interface ComponentClass<PropsType> {
new (props?: PropsType): Component<PropsType>;
}
export class Component<Props> extends HTMLElement {
// Special hack for own components type checking.
// It works in combination with ElementAttributesProperty. It placed in jsx.d.ts.
// more detail, see: https://www.typescriptlang.org/docs/handbook/jsx.html
// and https://github.com/skatejs/skatejs/pull/952#issuecomment-264500153
_props: Props & ComponentDefaultProps;
// this is not possible yet? ... without this we have to duplicate props definition with class props definition
// [K in keyof Props]: Props[K],

static readonly props: ComponentProps<any, any>;
static readonly observedAttributes: string[];

// Custom Elements v1
connectedCallback(): void;
disconnectedCallback(): void;
attributeChangedCallback(name: string, oldValue: null | string, newValue: null | string): void;
adoptedCallback?(): void;

// SkateJS life cycle
updatedCallback(previousProps: { [nameOrSymbol: string]: any }): boolean | void;
renderCallback(): VDOMElement<any> | VDOMElement<any>[] | null;
renderedCallback(): void;

// SkateJS DEPRECATED
static created?(elem: Component<any>): void;
static attached?(elem: Component<any>): void;
static detached?(elem: Component<any>): void;
static attributeChanged?(elem: Component<any>, data: { name: string, oldValue: null | string, newValue: null | string }): void;
static updated(elem: Component<any>, prevProps: { [nameOrSymbol: string]: any }): boolean;
static render?(elem: Component<any>): VDOMElement<any> | VDOMElement<any>[] | null;
static rendered?(elem: Component<any>): void;
}


type AttributeReflectionBaseType = boolean | string;
type AttributeReflectionConfig = AttributeReflectionBaseType | {
source?: AttributeReflectionBaseType,
target?: AttributeReflectionBaseType
}
export interface PropOptions<El, T> {
attribute?: AttributeReflectionConfig;
coerce?: (value: any) => T | null | undefined;
default?: T | null | undefined | ((elem: El, data: { name: string; }) => T | null | undefined);
deserialize?: (value: string | null) => T | null | undefined;
get?: <R>(elem: El, data: { name: string; internalValue: T; }) => R;
initial?: T | null | undefined | ((elem: El, data: { name: string; }) => T | null | undefined);
serialize?: (value: T | null | undefined) => string | null;
set?: (elem: El, data: { name: string; newValue: T | null | undefined; oldValue: T | null | undefined; }) => void;
}

export var define: {
(name: string, ctor: Function): any;
(ctor: Function): any;
};

export interface EmitOptions {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
detail?: any;
}
export function emit(elem: EventTarget, name: string, opts?: EmitOptions): void;

export var h: typeof vdom.element;

export function link(elem: Component<any>, target?: string): (e: Event) => void;

export var prop: {
create<T>(attr: PropOptions<any, T>): PropOptions<any, T> & ((attr: PropOptions<any, T>) => PropOptions<any, T>);

number(attr?: PropOptions<any, number>): PropOptions<any, number>;
boolean(attr?: PropOptions<any, boolean>): PropOptions<any, boolean>;
string(attr?: PropOptions<any, string>): PropOptions<any, string>;
array<T>(attr?: PropOptions<any, T[]>): PropOptions<any, T[]>;
object<T extends Object>(attr?: PropOptions<any, T>): PropOptions<any, T>;
};

export function props(elem: Component<any>, props?: any): void;

export function ready(elem: Component<any>, done: (c: Component<any>) => void): void;

// @DEPRECATED
// export var symbols: any;


//
// VDOM Nodes
// ----------------------------------------------------------------------

export interface VDOMElement<P> {
type: VDOMElementType<P>;
props: P;
key: Key | null;
}
type VDOMText = string | number;
type VDOMChild = VDOMElement<any> | VDOMText;

// Should be Array<VDOMNode> but type aliases cannot be recursive
type VDOMFragment = {} | Array<VDOMChild | any[] | boolean>;
type VDOMNode = VDOMChild | VDOMFragment | boolean | null | undefined;

type VDOMElementType<P> = string | { id: string } | ComponentClass<P> | SFC<P>;

export var vdom: {

element<P>(type: VDOMElementType<P>, attrs?: HTMLProps<HTMLElement> | P, ...children: VDOMChild[]): VDOMElement<any>,
element<P>(type: VDOMElementType<P>, ...children: VDOMChild[]): VDOMElement<any>,

builder(): typeof vdom.element;
builder(...tags: string[]): ((attrs?: HTMLProps<HTMLElement>, ...children: VDOMChild[]) => VDOMElement<any>)[];

attr(...args: any[]): void;
elementClose: Function;
elementOpen: Function;
elementOpenEnd: Function;
elementOpenStart: Function;
elementVoid: Function;
text: Function;
};
98 changes: 98 additions & 0 deletions src/ts-typings/common.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
export type Key = string | number;
export type Ref<T> = string | ((instance: T) => any);

interface Attributes {
key?: Key,
// this will be possible removed and added just to ClassAttributes because of https://github.com/skatejs/skatejs/issues/1020
slot?: string,
}
interface ClassAttributes<T> extends Attributes {
ref?: Ref<T>,
}

//
// JSX Related types
// ----------------------------------------------------------------------

export type HTMLProps<T extends Element> = Partial<T> & IncrementalHyperscriptAttributes<T>;
export type IncrementalHyperscriptAttributes<T> = IncrementalDomHTMLAttributes<T> & HyperscriptHTMLAttributes & HyperscriptEventHandler<T>;

interface IncrementalDomHTMLAttributes<T> {
key?: Key,
ref?: Ref<T>,
statics?: string[],
skip?: boolean,
}
interface HyperscriptHTMLAttributes {
class?: string,
}

interface HyperscriptEventHandler<T> {
onAbort?: typeof HTMLElement.prototype.onabort;
onActivate?: typeof HTMLElement.prototype.onactivate;
onBeforeactivate?: typeof HTMLElement.prototype.onbeforeactivate;
onBeforecopy?: typeof HTMLElement.prototype.onbeforecopy;
onBeforecut?: typeof HTMLElement.prototype.onbeforecut;
onBeforedeactivate?: typeof HTMLElement.prototype.onbeforedeactivate;
onBeforepaste?: typeof HTMLElement.prototype.onbeforepaste;
onBlur?: typeof HTMLElement.prototype.onblur;
onCanplay?: typeof HTMLElement.prototype.oncanplay;
onCanplaythrough?: typeof HTMLElement.prototype.oncanplaythrough;
onChange?: typeof HTMLElement.prototype.onchange;
onClick?: typeof HTMLElement.prototype.onclick;
onContextmenu?: typeof HTMLElement.prototype.oncontextmenu;
onCopy?: typeof HTMLElement.prototype.oncopy;
onCuechange?: typeof HTMLElement.prototype.oncuechange;
onCut?: typeof HTMLElement.prototype.oncut;
onDblclick?: typeof HTMLElement.prototype.ondblclick;
onDeactivate?: typeof HTMLElement.prototype.ondeactivate;
onDrag?: typeof HTMLElement.prototype.ondrag;
onDragend?: typeof HTMLElement.prototype.ondragend;
onDragenter?: typeof HTMLElement.prototype.ondragenter;
onDragleave?: typeof HTMLElement.prototype.ondragleave;
onDragover?: typeof HTMLElement.prototype.ondragover;
onDragstart?: typeof HTMLElement.prototype.ondragstart;
onDrop?: typeof HTMLElement.prototype.ondrop;
onDurationchange?: typeof HTMLElement.prototype.ondurationchange;
onEmptied?: typeof HTMLElement.prototype.onemptied;
onEnded?: typeof HTMLElement.prototype.onended;
onError?: typeof HTMLElement.prototype.onerror;
onFocus?: typeof HTMLElement.prototype.onfocus;
onInput?: typeof HTMLElement.prototype.oninput;
onInvalid?: typeof HTMLElement.prototype.oninvalid;
onKeydown?: typeof HTMLElement.prototype.onkeydown;
onKeypress?: typeof HTMLElement.prototype.onkeypress;
onKeyup?: typeof HTMLElement.prototype.onkeyup;
onLoad?: typeof HTMLElement.prototype.onload;
onLoadeddata?: typeof HTMLElement.prototype.onloadeddata;
onLoadedmetadata?: typeof HTMLElement.prototype.onloadedmetadata;
onLoadstart?: typeof HTMLElement.prototype.onloadstart;
onMousedown?: typeof HTMLElement.prototype.onmousedown;
onMouseenter?: typeof HTMLElement.prototype.onmouseenter;
onMouseleave?: typeof HTMLElement.prototype.onmouseleave;
onMousemove?: typeof HTMLElement.prototype.onmousemove;
onMouseout?: typeof HTMLElement.prototype.onmouseout;
onMouseover?: typeof HTMLElement.prototype.onmouseover;
onMouseup?: typeof HTMLElement.prototype.onmouseup;
onMousewheel?: typeof HTMLElement.prototype.onmousewheel;
onMscontentzoom?: typeof HTMLElement.prototype.onmscontentzoom;
onMsmanipulationstatechanged?: typeof HTMLElement.prototype.onmsmanipulationstatechanged;
onPaste?: typeof HTMLElement.prototype.onpaste;
onPause?: typeof HTMLElement.prototype.onpause;
onPlay?: typeof HTMLElement.prototype.onplay;
onPlaying?: typeof HTMLElement.prototype.onplaying;
onProgress?: typeof HTMLElement.prototype.onprogress;
onRatechange?: typeof HTMLElement.prototype.onratechange;
onReset?: typeof HTMLElement.prototype.onreset;
onScroll?: typeof HTMLElement.prototype.onscroll;
onSeeked?: typeof HTMLElement.prototype.onseeked;
onSeeking?: typeof HTMLElement.prototype.onseeking;
onSelect?: typeof HTMLElement.prototype.onselect;
onSelectstart?: typeof HTMLElement.prototype.onselectstart;
onStalled?: typeof HTMLElement.prototype.onstalled;
onSubmit?: typeof HTMLElement.prototype.onsubmit;
onSuspend?: typeof HTMLElement.prototype.onsuspend;
onTimeupdate?: typeof HTMLElement.prototype.ontimeupdate;
onVolumechange?: typeof HTMLElement.prototype.onvolumechange;
onWaiting?: typeof HTMLElement.prototype.onwaiting;
}

0 comments on commit 0c09adb

Please sign in to comment.