/
directive.ts
142 lines (122 loc) · 3.56 KB
/
directive.ts
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/**
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
import {Disconnectable, Part} from './lit-html.js';
export {
AttributePart,
BooleanAttributePart,
ChildPart,
ElementPart,
EventPart,
Part,
PropertyPart,
} from './lit-html.js';
export interface DirectiveClass {
new (part: PartInfo): Directive;
}
/**
* This utility type extracts the signature of a directive class's render()
* method so we can use it for the type of the generated directive function.
*/
export type DirectiveParameters<C extends Directive> = Parameters<C['render']>;
/**
* A generated directive function doesn't evaluate the directive, but just
* returns a DirectiveResult object that captures the arguments.
*/
export interface DirectiveResult<C extends DirectiveClass = DirectiveClass> {
/**
* This property needs to remain unminified.
* @internal */
['_$litDirective$']: C;
/** @internal */
values: DirectiveParameters<InstanceType<C>>;
}
export const PartType = {
ATTRIBUTE: 1,
CHILD: 2,
PROPERTY: 3,
BOOLEAN_ATTRIBUTE: 4,
EVENT: 5,
ELEMENT: 6,
} as const;
export type PartType = (typeof PartType)[keyof typeof PartType];
export interface ChildPartInfo {
readonly type: typeof PartType.CHILD;
}
export interface AttributePartInfo {
readonly type:
| typeof PartType.ATTRIBUTE
| typeof PartType.PROPERTY
| typeof PartType.BOOLEAN_ATTRIBUTE
| typeof PartType.EVENT;
readonly strings?: ReadonlyArray<string>;
readonly name: string;
readonly tagName: string;
}
export interface ElementPartInfo {
readonly type: typeof PartType.ELEMENT;
}
/**
* Information about the part a directive is bound to.
*
* This is useful for checking that a directive is attached to a valid part,
* such as with directive that can only be used on attribute bindings.
*/
export type PartInfo = ChildPartInfo | AttributePartInfo | ElementPartInfo;
/**
* Creates a user-facing directive function from a Directive class. This
* function has the same parameters as the directive's render() method.
*/
export const directive =
<C extends DirectiveClass>(c: C) =>
(...values: DirectiveParameters<InstanceType<C>>): DirectiveResult<C> => ({
// This property needs to remain unminified.
['_$litDirective$']: c,
values,
});
/**
* Base class for creating custom directives. Users should extend this class,
* implement `render` and/or `update`, and then pass their subclass to
* `directive`.
*/
export abstract class Directive implements Disconnectable {
//@internal
__part!: Part;
//@internal
__attributeIndex: number | undefined;
//@internal
__directive?: Directive;
//@internal
_$parent!: Disconnectable;
// These will only exist on the AsyncDirective subclass
//@internal
_$disconnectableChildren?: Set<Disconnectable>;
// This property needs to remain unminified.
//@internal
['_$notifyDirectiveConnectionChanged']?(isConnected: boolean): void;
constructor(_partInfo: PartInfo) {}
// See comment in Disconnectable interface for why this is a getter
get _$isConnected() {
return this._$parent._$isConnected;
}
/** @internal */
_$initialize(
part: Part,
parent: Disconnectable,
attributeIndex: number | undefined
) {
this.__part = part;
this._$parent = parent;
this.__attributeIndex = attributeIndex;
}
/** @internal */
_$resolve(part: Part, props: Array<unknown>): unknown {
return this.update(part, props);
}
abstract render(...props: Array<unknown>): unknown;
update(_part: Part, props: Array<unknown>): unknown {
return this.render(...props);
}
}