-
Notifications
You must be signed in to change notification settings - Fork 0
/
stamp-collection.ts
104 lines (97 loc) · 3.07 KB
/
stamp-collection.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
import { Component, ContextComponent } from './component.js'
/**
* Property filter function for a Stamp alternative
*/
// Want to be forgiving in what we accept
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type StampPropertiesApply<Props = any> = (properties: Props) => boolean
export type StampAlternatives = Array<
[StampPropertiesApply, HTMLTemplateElement]
>
export type PrestampApplies = [Component, StampPropertiesApply]
/**
* A collection of Stamps that include the static DOM elements of Butterfloat components
*/
export class StampCollection {
readonly #map = new WeakMap<Component, StampAlternatives>()
readonly #prestampMap = new WeakMap<
Element | DocumentFragment,
PrestampApplies
>()
/**
* Get a Stamp for a component, given applicable properties
* @param c Component
* @param properties Properties that apply to the component
* @returns A stamp
*/
getStamp(c: Component, properties: unknown): HTMLTemplateElement | undefined {
const alternatives = this.#map.get(c)
if (alternatives) {
for (const [applies, stamp] of alternatives) {
if (applies(properties)) {
return stamp
}
}
}
}
/**
* Check if a container was registered as a prestamp for this component with given properties
* @param c Component
* @param properties Properties that apply to the component
* @param container Container to test for prestamp
* @returns Is registered as a valid prestamp
*/
isPrestamp(
c: Component,
properties: unknown,
container: Element | DocumentFragment,
): boolean {
const stampApplies = this.#prestampMap.get(container)
if (stampApplies) {
return stampApplies[0] === c && stampApplies[1](properties)
}
return false
}
/**
* Register one Stamp for all possible properties for the given Component
* @param c Component
* @param stamp Stamp to register
* @returns this (for chaining)
*/
registerOnlyStamp(c: Component, stamp: HTMLTemplateElement): StampCollection {
this.#map.set(c, [[(_) => true, stamp]])
return this
}
/**
* Register a possible Stamp for subset of possible properties for the given Component
* @param c Component
* @param when Property filter for when the Stamp applies
* @param stamp Stamp to register
* @returns this (for chaining)
*/
registerStampAlternative<Props>(
c: ContextComponent<Props>,
when: StampPropertiesApply<Props>,
stamp: HTMLTemplateElement,
): StampCollection {
const alternatives = this.#map.get(c) ?? []
alternatives.push([when, stamp])
this.#map.set(c, alternatives)
return this
}
/**
* Register a container that was pre-stamped
* @param c Component
* @param container Prestamped container
* @param when Property filter for when the prestamp applies
* @returns this (for chaining)
*/
registerPrestamp<Props>(
c: Component,
container: Element | DocumentFragment,
when?: StampPropertiesApply<Props>,
): StampCollection {
this.#prestampMap.set(container, [c, when ?? (() => true)])
return this
}
}