1
1
import { ObservableMap } from "./observable-map.js" ;
2
- import { createContext , ContextEvent , UnknownContext } from "./context-protocol.js" ;
2
+ import {
3
+ createContext ,
4
+ ContextEvent ,
5
+ UnknownContext ,
6
+ } from "./context-protocol.js" ;
3
7
4
- interface CustomElement extends HTMLElement {
5
- new ( ...args : any [ ] ) : CustomElement ;
6
- observedAttributes : string [ ] ;
8
+ export interface CustomElement extends Element {
7
9
connectedCallback ?( ) : void ;
8
10
attributeChangedCallback ?(
9
11
name : string ,
@@ -12,26 +14,47 @@ interface CustomElement extends HTMLElement {
12
14
) : void ;
13
15
disconnectedCallback ?( ) : void ;
14
16
adoptedCallback ?( ) : void ;
17
+ formAssociatedCallback ?( form : HTMLFormElement ) : void ;
18
+ formDisabledCallback ?( disabled : boolean ) : void ;
19
+ formResetCallback ?( ) : void ;
20
+ formStateRestoreCallback ?(
21
+ state : unknown ,
22
+ reason : "autocomplete" | "restore" ,
23
+ ) : void ;
15
24
}
16
25
17
- export function ProviderMixin ( Class : CustomElement ) : CustomElement {
26
+ export declare type Constructor < T > = new ( ...args : any [ ] ) => T ;
27
+
28
+ type ProviderElement = CustomElement & {
29
+ contexts ?: Record < PropertyKey , ( ) => unknown > ;
30
+ updateContext ?( name : string , value : unknown ) : void ;
31
+ } ;
32
+
33
+ type ConsumerElement = CustomElement & {
34
+ contexts ?: Record < PropertyKey , ( data : any ) => void > ;
35
+ } ;
36
+
37
+ export function ProviderMixin < T extends Constructor < ProviderElement > > (
38
+ Class : T ,
39
+ ) : T & Constructor < ProviderElement > {
18
40
return class extends Class {
19
41
#dataStore = new ObservableMap ( ) ;
20
42
21
43
connectedCallback ( ) {
22
44
super . connectedCallback ?.( ) ;
23
45
24
- // @ts -expect-error todo
25
- for ( const [ key , value ] of Object . entries ( this . contexts || { } ) ) {
26
- // @ts -expect-error todo
46
+ const contexts = "contexts" in this ? this . contexts : { } ;
47
+
48
+ for ( const [ key , value ] of Object . entries ( contexts || { } ) ) {
27
49
this . #dataStore. set ( key , value ( ) ) ;
28
50
}
29
51
30
- this . addEventListener ( ' context-request' , this ) ;
52
+ this . addEventListener ( " context-request" , this ) ;
31
53
}
32
54
33
55
disconnectedCallback ( ) : void {
34
56
this . #dataStore = new ObservableMap ( ) ;
57
+ this . removeEventListener ( "context-request" , this ) ;
35
58
}
36
59
37
60
handleEvent ( event : Event ) {
@@ -72,15 +95,29 @@ export function ProviderMixin(Class: CustomElement): CustomElement {
72
95
} ;
73
96
}
74
97
75
- export function ConsumerMixin ( Class : CustomElement ) : CustomElement {
98
+ export function ConsumerMixin < T extends Constructor < ConsumerElement > > (
99
+ Class : T ,
100
+ ) : T & Constructor < ConsumerElement > {
76
101
return class extends Class {
77
- unsubscribes : Array < ( ) => void > = [ ] ;
102
+ #unsubscribes: Array < ( ) => void > = [ ] ;
103
+
104
+ getContext ( contextName : string ) {
105
+ let result ;
106
+
107
+ this . dispatchEvent (
108
+ new ContextEvent ( createContext ( contextName ) , ( data ) => {
109
+ result = data ;
110
+ } ) ,
111
+ ) ;
112
+
113
+ return result ;
114
+ }
78
115
79
116
connectedCallback ( ) {
80
117
super . connectedCallback ?.( ) ;
81
118
82
- // @ts -expect-error don't worry about it babe
83
- for ( const [ contextName , callback ] of Object . entries ( this . contexts ) ) {
119
+ const contexts = "contexts" in this ? this . contexts : { } ;
120
+ for ( const [ contextName , callback ] of Object . entries ( contexts || { } ) ) {
84
121
const context = createContext ( contextName ) ;
85
122
86
123
// We dispatch a event with that context. The event will bubble up the tree until it
@@ -90,10 +127,9 @@ export function ConsumerMixin(Class: CustomElement): CustomElement {
90
127
new ContextEvent (
91
128
context ,
92
129
( data , unsubscribe ) => {
93
- // @ts -expect-error
94
130
callback ( data ) ;
95
131
if ( unsubscribe ) {
96
- this . unsubscribes . push ( unsubscribe ) ;
132
+ this . # unsubscribes. push ( unsubscribe ) ;
97
133
}
98
134
} ,
99
135
// Always subscribe. Consumers can ignore updates if they'd like.
@@ -105,12 +141,12 @@ export function ConsumerMixin(Class: CustomElement): CustomElement {
105
141
106
142
// Unsubscribe from all callbacks when disconnecting
107
143
disconnectedCallback ( ) {
108
- for ( const unsubscribe of this . unsubscribes ) {
144
+ for ( const unsubscribe of this . # unsubscribes) {
109
145
unsubscribe ?.( ) ;
110
146
}
111
147
// Empty out the array in case this element is still stored in memory but just not connected
112
148
// to the DOM.
113
- this . unsubscribes = [ ] ;
149
+ this . # unsubscribes = [ ] ;
114
150
}
115
151
} ;
116
152
}
0 commit comments