Skip to content

Commit

Permalink
Merge pull request #86 from lightning-js/fix/typedefs
Browse files Browse the repository at this point in the history
Updates TypeScript type definitions
  • Loading branch information
michielvandergeest authored May 8, 2024
2 parents 963fc2c + 73cd27e commit 7b90a40
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 48 deletions.
20 changes: 10 additions & 10 deletions src/application.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {default as Component, ComponentInstance} from './component'
import {default as Component} from './component'

declare namespace Application {

Expand Down Expand Up @@ -84,10 +84,6 @@ declare namespace Application {
politeness?: 'off' | 'polite' | 'assertive'
}

function Application(
config: Application.ApplicationConfig
) : Application.ApplicationInstance

type RequireAtLeastOne<T> = {
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>
}[keyof T]
Expand All @@ -104,7 +100,7 @@ declare namespace Application {
/**
* Component to load when activating the route
*/
component: typeof ComponentInstance,
component: Component,
/**
* Transition configuration for the route
*/
Expand Down Expand Up @@ -142,9 +138,9 @@ declare namespace Application {
}
}

export interface ApplicationInstance extends ComponentInstance {}
export interface ApplicationInstance extends Component.ComponentInstance {}

export interface ApplicationConfig extends Component.ComponentConfig {
export interface ApplicationConfig<Props extends string, S, M> extends Component.ComponentConfig<Props, S, M> {
/**
* Routes definition
*
Expand All @@ -167,8 +163,12 @@ declare namespace Application {
*
* Root App component
*/
declare function Application(
config: Application.ApplicationConfig
declare function Application<
Props extends string,
S extends Component.State,
M extends Component.Methods
>(
config: Application.ApplicationConfig<Props, S, M>
) : Application.ApplicationInstance

export default Application;
195 changes: 157 additions & 38 deletions src/component.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,47 @@ declare namespace Component {
*/
type Name = string


interface Announcer {
/**
* Announce a message to screen readers by specifying the politeness level
*/
speak: (message: string, politeness?: 'polite' | 'assertive') => void

/**
* Announce a message to screen readers with a polite politeness level
*/
polite: (message: string) => void

/**
* Announce a message to screen readers with an assertive politeness level
*/
assertive: (message: string) => void

/**
* Stop all announcements
*/
stop: () => void
}

interface Log {
/**
* Log an info message
*/
info(...args): typeof console.info
/**
* Log an error message
*/
error(...args): typeof console.error
/**
* Log a warning
*/
warn(...args): typeof console.warn
/**
* Log a debug message
*/
debug(...args): typeof console.debug
}
interface AdvancedProp {
/**
* Name of the prop
Expand All @@ -48,115 +89,175 @@ declare namespace Component {
*/
cast?: () => any
}
type PropsArray<T extends string> = T[]
type AdvancedProps = AdvancedProp[]

type Props = string | AdvancedProp
// type ExtractPropNames<T extends Prop[]> = T extends (infer U)[]
// ? U extends string
// ? U
// : U extends AdvancedProp
// ? U['key']
// : never
// : never;

type NotFunction<T> = T extends Function ? never : T;

/**
* Internal state of a Component instance
*/
interface StateObject {
interface State {
[key: string]: any
}

interface Computed {
[key: string]: (this: ComponentInstance) => any
interface Computed<S, M, P> {
[key: string]: (this: ComponentInstance & S & M & P) => any
}

interface Watch {
[key: string]: (this: ComponentInstance, value: any, oldValue: any) => void
interface Watch<S, M, P> {
[key: string]: (this: ComponentInstance & S & M & P, value: any, oldValue: any) => void
}

interface Methods {
[key: string]: (this: ComponentInstance) => any
[key: string]: (this: ComponentInstance & State & Methods, ...args: any) => any;
}

interface Input {
[key: string]: (this: ComponentInstance, event: KeyboardEvent) => void,
// interface MethodsExtended<S, M, P> extends Methods {
// [key: string]: (this: ComponentInstance & S & M & P) => any;
// }

interface Input<S, M, P> {
[key: string]: ((this: ComponentInstance & S & M & P, event: KeyboardEvent) => void) | undefined,

/**
* Catch all input function
*
* Will be invoked when there is no dedicated function for a certain key
*/
'any'?: (this: ComponentInstance, event: KeyboardEvent) => void,
*/
any?: (this: ComponentInstance & S & M & P, event: KeyboardEvent) => void,
}

interface Log {
/**
* Log an info message
*/
info: typeof console.info
info(...args): typeof console.info
/**
* Log an error message
*/
error: typeof console.error
error(...args): typeof console.error
/**
* Log a warning
*/
warn: typeof console.warn
warn(...args): typeof console.warn
/**
* Log a debug message
*/
debug: typeof console.debug
debug(...args): typeof console.debug
}

interface Hooks {
interface Hooks<S, M, P> {
/**
* Fires when the Component is being instantiated.
* At this moment child elements will not be available yet
*/
init?: (this: ComponentInstance) => void
init?: (this: ComponentInstance & S & M & P, ...args: any) => void
/**
* Fires when the Component is fully initialized and ready for interaction.
*/
ready?: (this: ComponentInstance) => void
ready?: (this: ComponentInstance & S & M & P, ...args: any) => void
/**
* Triggers when the Component receives focus.
*
* This event can fire multiple times during the component's lifecycle
*/
focus?: (this: ComponentInstance) => void
focus?: (this: ComponentInstance & S & M & P, ...args: any) => void
/**
* Triggers when the Component loses focus.
*
* This event can fire multiple times during the component's lifecycle
*/
unfocus?: (this: ComponentInstance) => void
unfocus?: (this: ComponentInstance & S & M & P, ...args: any) => void
/**
* Fires when the Component is being destroyed and removed.
*/
destroy?: (this: ComponentInstance) => void,
destroy?: (this: ComponentInstance & S & M & P, ...args: any) => void,
/**
* Fires upon each frame start (allowing you to tap directly into the renderloop)
*
* Note: This hook will fire continuously, multiple times per second!
*/
frameTick?: (this: ComponentInstance) => void,
frameTick?: (this: ComponentInstance & S & M & P, ...args: any) => void,
/**
* Fires when the component enters the viewport _margin_ and is attached to the render tree
*
* This event can fire multiple times during the component's lifecycle
*/
attach?: (this: ComponentInstance) => void,
attach?: (this: ComponentInstance & S & M & P, ...args: any) => void,
/**
* Fires when the component leaves the viewport _margin_ and is detached from the render tree
*
* This event can fire multiple times during the component's lifecycle
*/
detach?: (this: ComponentInstance) => void,
detach?: (this: ComponentInstance & S & M & P, ...args: any) => void,
/**
* Fires when the component enters the visible viewport
*
* This event can fire multiple times during the component's lifecycle
*/
enter?: (this: ComponentInstance) => void,
enter?: (this: ComponentInstance & S & M & P, ...args: any) => void,
/**
* Fires when the component leaves the visible viewport
*
* This event can fire multiple times during the component's lifecycle
*/
exit?: (this: ComponentInstance) => void,
exit?: (this: ComponentInstance & S & M & P, ...args: any) => void,
}

/**
* Route object
*/
interface Route {
path: string,
params: Record<string, string>,
options?: {
inHistory?: boolean,
keepAlive?: boolean,
[key: string]: any,
},
data?: Record<string, any>,
component?: (args: { props: any }, holder: any, context: any) => Promise<any>,
hooks?: {
before?: (route: Route, previousRoute: Route) => Promise<string | Route | void>,
}
}


interface Router {
/**
* Navigate to a different location
*/
to(location: string, data?: Record<string, any>, options?: Record<string, any>): void;

/**
* Navigate to the previous location
*/
back(): boolean;

/**
* Get the current route read-only
*/
readonly currentRoute: Route;

/**
* Get the list of all routes
*/
readonly routes: Route[];

/**
* Get navigating state
*/
readonly navigating: boolean;

}

export interface ComponentInstance {
Expand Down Expand Up @@ -217,15 +318,29 @@ declare namespace Component {
*/
select: (ref: string) => ComponentInstance | ElementInstance

// tmp
[key: string]: any
/**
* Announcer methods for screen reader support
*/
$announcer: Announcer

/**
* Triggers a forced update on state variables.
*/
$trigger: (key: string) => void
trigger: (key: string) => void

/**
* Router instance
*/
$router: Router

}

export interface ElementInstance {
focus?: () => void
}

export interface ComponentConfig {
export interface ComponentConfig<Props extends string, S, M> {
components?: any,
/**
* XML-based template string of the Component
Expand Down Expand Up @@ -261,7 +376,7 @@ declare namespace Component {
* }
* ```
*/
state?: (this: ComponentInstance) => StateObject,
state?: (this: { [K in Props]: any}) => S,
/**
* Allowed props to be passed into the Component by the parent
*
Expand All @@ -279,37 +394,41 @@ declare namespace Component {
* }]
* ```
*/
props?: Props[],
props?: PropsArray<Props> | AdvancedProp[],
/**
* Computed properties
*/
computed?: Computed,
computed?: Computed<S, M, { [K in Props]: any}>,
/**
* Watchers for changes to state variables, props or computed properties
*/
watch?: Watch,
watch?: Watch<S, M, { [K in Props]: any}>,
/**
* Hooking into Lifecycle events
*/
hooks?: Hooks,
hooks?: Hooks<S, M, { [K in Props]: any}>,
/**
* Methods for abstracting more complex business logic into separate function
*/
methods?: Methods,
methods?: M //MethodsExtended<S, M, { [K in Props]: any}>,
/**
* Tapping into user input
*/
input?: Input
input?: Input<S, M, { [K in Props]: any}>
}
}


/**
* Blits.Component()
*/
declare function Component(
declare function Component<
Props extends string,
S extends Component.State,
M extends Component.Methods
>(
name: Component.Name,
config: Component.ComponentConfig,
config: Component.ComponentConfig<Props, S, M>
) : Component.ComponentInstance

export default Component;
Loading

0 comments on commit 7b90a40

Please sign in to comment.