-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcomponent.ts
More file actions
71 lines (53 loc) · 2.29 KB
/
component.ts
File metadata and controls
71 lines (53 loc) · 2.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import type { ElementKey, Instance, DarkElement, RefProps, KeyProps, Prettify } from '../shared';
import { KEY_ATTR } from '../constants';
const $$inject = Symbol('inject');
class Component<P extends StandardComponentProps = {}> {
type: CreateElement<P> = null;
props: P = null;
token?: Symbol = null;
displayName?: string = null;
shouldUpdate?: ShouldUpdate<P> = null;
children: Array<Instance> = null;
constructor(type: CreateElement<P>, token: Symbol, props: P, shouldUpdate: ShouldUpdate<P>, displayName: string) {
this.type = type;
this.props = props;
token && (this.token = token);
shouldUpdate && (this.shouldUpdate = shouldUpdate);
displayName && (this.displayName = displayName);
}
}
function component<P extends object>(type: CreateElement<P>, options: ComponentOptions = {}) {
const { token: $token, displayName } = options;
type Props = P & StandardComponentProps;
const factory: ComponentFactoryWithPossiblyInject<Props> = (props = {} as Props) => {
const { token = $token, shouldUpdate } = factory[$$inject] || defaultInject;
return new Component(type, token, props, shouldUpdate, displayName);
};
factory.displayName = displayName;
return factory as ComponentFactory<Prettify<Props>>;
}
const defaultInject: ComponentInject = {};
const detectIsComponent = (x: unknown): x is Component => x instanceof Component;
const getComponentKey = (x: Component): ElementKey => x.props[KEY_ATTR] ?? null;
const hasComponentFlag = (inst: Component, flag: string) => Boolean(inst.props[flag]);
type ComponentOptions = Readonly<{
displayName?: string;
token?: Symbol;
}>;
type ComponentFactoryWithPossiblyInject<P extends object = {}> = {
(props?: P): Component<P>;
[$$inject]?: ComponentInject<P>;
displayName: string;
};
type CreateElement<P extends StandardComponentProps> = (props: P) => DarkElement;
export type ComponentInject<P extends object = {}> = Readonly<{
token?: Symbol;
shouldUpdate?: ShouldUpdate<P>;
}>;
export type ShouldUpdate<P> = (prevProps: P, nextProps: P) => boolean;
export type StandardComponentProps = KeyProps & RefProps;
export type ComponentFactory<P extends object = {}> = {
(props?: P): Component<P>;
displayName?: string;
};
export { Component, component, $$inject, detectIsComponent, getComponentKey, hasComponentFlag };