@bodil/dom 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/component.d.ts +218 -6
- package/dist/component.js +154 -13
- package/dist/component.js.map +1 -1
- package/dist/css.d.ts +4 -0
- package/dist/css.js +4 -0
- package/dist/css.js.map +1 -1
- package/dist/decorators/attribute.js +1 -1
- package/dist/decorators/attribute.js.map +1 -1
- package/dist/decorators/connect.test.js +1 -1
- package/dist/decorators/connect.test.js.map +1 -1
- package/dist/decorators/reactive.d.ts +1 -1
- package/dist/decorators/reactive.js +1 -1
- package/dist/decorators/reactive.js.map +1 -1
- package/dist/decorators/reactive.test.js +1 -1
- package/dist/decorators/reactive.test.js.map +1 -1
- package/dist/dom.d.ts +32 -0
- package/dist/dom.js +32 -0
- package/dist/dom.js.map +1 -1
- package/dist/emitter.d.ts +8 -0
- package/dist/emitter.js.map +1 -1
- package/dist/event.d.ts +4 -0
- package/dist/event.js.map +1 -1
- package/dist/geometry.d.ts +7 -0
- package/dist/geometry.js +4 -0
- package/dist/geometry.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/signal.d.ts +29 -0
- package/dist/signal.js +78 -0
- package/dist/signal.js.map +1 -0
- package/dist/signal.test.d.ts +1 -0
- package/dist/signal.test.js +135 -0
- package/dist/signal.test.js.map +1 -0
- package/package.json +16 -8
- package/src/component.ts +237 -20
- package/src/css.ts +5 -0
- package/src/decorators/attribute.ts +1 -1
- package/src/decorators/connect.test.ts +1 -1
- package/src/decorators/reactive.test.ts +1 -1
- package/src/decorators/reactive.ts +4 -4
- package/src/dom.ts +33 -0
- package/src/emitter.ts +8 -0
- package/src/event.ts +4 -0
- package/src/geometry.ts +8 -0
- package/src/index.ts +2 -1
- package/src/signal.test.ts +89 -0
- package/src/signal.ts +109 -0
package/dist/component.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web component base class.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
import { type Disposifiable } from "@bodil/core/disposable";
|
|
2
6
|
import { Signal } from "@bodil/signal";
|
|
3
7
|
import { type CSSResult, type CSSResultOrNative, type ReactiveController, type ReactiveControllerHost, type RenderOptions } from "lit";
|
|
@@ -21,15 +25,51 @@ export type Deps = Array<typeof HTMLElement>;
|
|
|
21
25
|
export type CSSStyleSpec = CSSResult | CSSStyleSheet | string;
|
|
22
26
|
export type CSSStyleSpecArray = Array<CSSStyleSpec | CSSStyleSpecArray>;
|
|
23
27
|
export type CSSStyleSpecDeclaration = CSSStyleSpec | CSSStyleSpecArray;
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown when a {@link Component.render} method causes infinite
|
|
30
|
+
* re-renders.
|
|
31
|
+
*/
|
|
24
32
|
export declare class ComponentUpdateLoopError extends Error {
|
|
25
33
|
constructor(message?: string, options?: ErrorOptions);
|
|
26
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Base class for web components.
|
|
37
|
+
*/
|
|
27
38
|
export declare abstract class Component extends EmitterElement implements ReactiveControllerHost, Disposable {
|
|
28
39
|
#private;
|
|
40
|
+
/**
|
|
41
|
+
* Declare the web components this element will be using.
|
|
42
|
+
*
|
|
43
|
+
* This is a convenient place to make sure these web components will be
|
|
44
|
+
* defined when your component is rendered. It has no effect otherwise.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* class MyComponent extends Component {
|
|
48
|
+
* static deps: Deps = [ MySubcomponent, MyOtherSubcomponent ];
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
29
51
|
static deps: Deps;
|
|
52
|
+
/**
|
|
53
|
+
* Declare CSS style sheets which will be installed for this web component.
|
|
54
|
+
*
|
|
55
|
+
* Style sheets can be either {@link CSSStyleSheet} objects,
|
|
56
|
+
* Lit template {@link CSSResult}s, or strings.
|
|
57
|
+
*
|
|
58
|
+
* If a superclass also declares the `styles` property, this list will be
|
|
59
|
+
* appended to the superclass's list.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* class MyComponent extends Component {
|
|
63
|
+
* static styles = css`
|
|
64
|
+
* :host {
|
|
65
|
+
* border: 2px solid red;
|
|
66
|
+
* }
|
|
67
|
+
* `;
|
|
68
|
+
* }
|
|
69
|
+
*/
|
|
30
70
|
static styles?: CSSStyleSpecDeclaration;
|
|
31
71
|
static shadowRootOptions: ShadowRootInit;
|
|
32
|
-
static initialisers
|
|
72
|
+
private static initialisers;
|
|
33
73
|
/** @ignore */
|
|
34
74
|
protected static attributeConfig: Map<string, AttributeConfig>;
|
|
35
75
|
/** @ignore */
|
|
@@ -40,33 +80,155 @@ export declare abstract class Component extends EmitterElement implements Reacti
|
|
|
40
80
|
renderOptions: RenderOptions;
|
|
41
81
|
emits: object;
|
|
42
82
|
readonly renderRoot: ShadowRoot | HTMLElement;
|
|
83
|
+
/**
|
|
84
|
+
* True if this component had scheduled an update which has not yet started.
|
|
85
|
+
*/
|
|
43
86
|
get isUpdatePending(): boolean;
|
|
44
87
|
get updateComplete(): Promise<boolean>;
|
|
88
|
+
/**
|
|
89
|
+
* A {@link Promise} which resolves when this component has completed its
|
|
90
|
+
* first update and considers itself stabilised, according to the
|
|
91
|
+
* {@link Component.stabilise} method.
|
|
92
|
+
*
|
|
93
|
+
* By default, a component considers itself stabilised when all of its
|
|
94
|
+
* children which are also {@link Component}s are reporting as stabilised.
|
|
95
|
+
*/
|
|
45
96
|
get hasStabilised(): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* An {@link AbortSignal} which will trigger when this component is
|
|
99
|
+
* disconnected from the DOM.
|
|
100
|
+
*
|
|
101
|
+
* This can be passed along to asynchronous tasks such as {@link fetch}
|
|
102
|
+
* initiated by this component, which will then be aborted automatically if
|
|
103
|
+
* the component is removed from the DOM.
|
|
104
|
+
*/
|
|
46
105
|
get abortSignal(): AbortSignal;
|
|
47
|
-
|
|
48
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Register a function which will be executed whenever an instance of this
|
|
108
|
+
* class is constructed.
|
|
109
|
+
*/
|
|
110
|
+
static addInitialiser(init: (this: Component) => void): void;
|
|
111
|
+
/**
|
|
112
|
+
* A list of the attributes this element has declared.
|
|
113
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#responding_to_attribute_changes
|
|
114
|
+
* @internal
|
|
115
|
+
*/
|
|
116
|
+
static get observedAttributes(): ReadonlyArray<string>;
|
|
49
117
|
private static finalise;
|
|
118
|
+
/** @ignore */
|
|
50
119
|
constructor();
|
|
120
|
+
/**
|
|
121
|
+
* This lifecycle callback is called when the component is attached to the
|
|
122
|
+
* DOM.
|
|
123
|
+
*
|
|
124
|
+
* Generally, prefer using methods with @{@link connect} decorators to
|
|
125
|
+
* overriding this method.
|
|
126
|
+
*/
|
|
51
127
|
protected connectedCallback(): void;
|
|
128
|
+
/**
|
|
129
|
+
* This lifecycle callback is called when the component is removed from the
|
|
130
|
+
* DOM.
|
|
131
|
+
*
|
|
132
|
+
* Generally, prefer using methods with @{@link connect} decorators to
|
|
133
|
+
* overriding this method.
|
|
134
|
+
*/
|
|
52
135
|
protected disconnectedCallback(): void;
|
|
136
|
+
/**
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
53
139
|
setAttributeQuietly(name: string, value: string | null): void;
|
|
140
|
+
/**
|
|
141
|
+
* @internal
|
|
142
|
+
*/
|
|
54
143
|
protected attributeChangedCallback(name: string, old: string | null, valueString: string | null): void;
|
|
55
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Typedoc does *not* like this type signature. TODO figure out how to
|
|
146
|
+
* document it properly.
|
|
147
|
+
* @ignore
|
|
148
|
+
*/
|
|
149
|
+
$signal<K extends keyof this & string, V extends this[K]>(prop: K): Signal.Computed<V>;
|
|
56
150
|
addController(controller: ReactiveController): void;
|
|
57
151
|
removeController(controller: ReactiveController): void;
|
|
152
|
+
/**
|
|
153
|
+
* Create the component's render root.
|
|
154
|
+
*
|
|
155
|
+
* By default, this creates a {@link ShadowRoot} and attaches it to the
|
|
156
|
+
* component.
|
|
157
|
+
*
|
|
158
|
+
* If you don't want to use a shadow DOM, you can override this method to
|
|
159
|
+
* just `return this`, which causes the component's contents to render as
|
|
160
|
+
* direct children of the component itself.
|
|
161
|
+
*/
|
|
58
162
|
protected createRenderRoot(): HTMLElement | ShadowRoot;
|
|
163
|
+
/**
|
|
164
|
+
* Ask this component to update itself.
|
|
165
|
+
*/
|
|
59
166
|
requestUpdate(opts?: UpdateConfig): void;
|
|
167
|
+
/**
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
60
170
|
hasRequiredProperties(): Signal.Computed<boolean>;
|
|
171
|
+
/** @internal */
|
|
61
172
|
protected performUpdate(): Promise<void>;
|
|
173
|
+
/** @internal */
|
|
62
174
|
protected update(): void;
|
|
175
|
+
/**
|
|
176
|
+
* Return an iterator over this component's children which are also
|
|
177
|
+
* {@link Component}s.
|
|
178
|
+
*/
|
|
63
179
|
protected findChildComponents(root?: Element | ShadowRoot): IteratorObject<Component>;
|
|
180
|
+
/**
|
|
181
|
+
* Return a {@link Promise} which resolves when this component considers
|
|
182
|
+
* itself to have stabilised.
|
|
183
|
+
*
|
|
184
|
+
* The default implementation waits for any children which are also
|
|
185
|
+
* {@link Component}s to report that they have also stabilised.
|
|
186
|
+
*/
|
|
64
187
|
protected stabilise(): Promise<void>;
|
|
188
|
+
/**
|
|
189
|
+
* This lifecycle callback is called each time an update has completed.
|
|
190
|
+
*/
|
|
65
191
|
protected updated(): void;
|
|
192
|
+
/**
|
|
193
|
+
* This lifecycle callback is called after the component's first update has
|
|
194
|
+
* completed, and before {@link Component.updated}.
|
|
195
|
+
*/
|
|
66
196
|
protected firstUpdated(): void;
|
|
197
|
+
/**
|
|
198
|
+
* This lifecycle callback is called when the component considers itself
|
|
199
|
+
* stabilised after its first update.
|
|
200
|
+
*
|
|
201
|
+
* @see {@link Component.hasStabilised}
|
|
202
|
+
*/
|
|
67
203
|
protected stabilised(): void;
|
|
204
|
+
/**
|
|
205
|
+
* This lifecycle callback is called every time a property decorated with
|
|
206
|
+
* the @{@link require} decorator has changed, but only when every property
|
|
207
|
+
* marked as such is not `undefined`.
|
|
208
|
+
*/
|
|
68
209
|
protected initialised(): void;
|
|
210
|
+
/**
|
|
211
|
+
* This lifecycle callback is called the first time every property decorated
|
|
212
|
+
* with @{@link require} has been defined, and before
|
|
213
|
+
* {@link Component.initialised}.
|
|
214
|
+
*/
|
|
69
215
|
protected firstInitialised(): void;
|
|
216
|
+
/**
|
|
217
|
+
* Render the component's contents.
|
|
218
|
+
*
|
|
219
|
+
* This function should return a Lit [renderable
|
|
220
|
+
* value](https://lit.dev/docs/templates/expressions/#child-expressions),
|
|
221
|
+
* usually an {@link html} template.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* class MyComponent extends Component {
|
|
225
|
+
* protected override render() {
|
|
226
|
+
* return html`
|
|
227
|
+
* <h1>Hello Joe!</h1>
|
|
228
|
+
* `;
|
|
229
|
+
* }
|
|
230
|
+
* }
|
|
231
|
+
*/
|
|
70
232
|
protected render(): unknown;
|
|
71
233
|
[Symbol.dispose](): void;
|
|
72
234
|
/**
|
|
@@ -102,18 +264,70 @@ export declare abstract class Component extends EmitterElement implements Reacti
|
|
|
102
264
|
* element. Otherwise, return null.
|
|
103
265
|
*/
|
|
104
266
|
getFocusedElement(): Element | null;
|
|
267
|
+
/**
|
|
268
|
+
* Find the first element in the component's {@link Component.renderRoot}
|
|
269
|
+
* matching the provided CSS selector.
|
|
270
|
+
*
|
|
271
|
+
* If you need to query the component's direct child elements instead, use
|
|
272
|
+
* {@link Component.querySlot}.
|
|
273
|
+
*
|
|
274
|
+
* If you were looking for Lit's `@query` decorator, use this as a getter
|
|
275
|
+
* instead, as in the example below.
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* class MyComponent extends Component {
|
|
279
|
+
* get button(): HTMLButtonElement {
|
|
280
|
+
* return this.query("button");
|
|
281
|
+
* }
|
|
282
|
+
*
|
|
283
|
+
* protected override render() {
|
|
284
|
+
* return html`<button>I am a button</button>`;
|
|
285
|
+
* }
|
|
286
|
+
* }
|
|
287
|
+
*/
|
|
105
288
|
query<El extends keyof HTMLElementTagNameMap>(selector: El): HTMLElementTagNameMap[El] | null;
|
|
106
289
|
query<El extends keyof SVGElementTagNameMap>(selector: El): SVGElementTagNameMap[El] | null;
|
|
107
290
|
query<El extends keyof MathMLElementTagNameMap>(selector: El): MathMLElementTagNameMap[El] | null;
|
|
108
291
|
/** @deprecated */
|
|
109
292
|
query<El extends keyof HTMLElementDeprecatedTagNameMap>(selector: El): HTMLElementDeprecatedTagNameMap[El] | null;
|
|
110
293
|
query(selector: string): Element | null;
|
|
294
|
+
/**
|
|
295
|
+
* Find all elements in the component's {@link Component.renderRoot}
|
|
296
|
+
* matching the provided CSS selector.
|
|
297
|
+
*
|
|
298
|
+
* If you need to query the component's direct child elements instead, use
|
|
299
|
+
* {@link Component.querySlot}.
|
|
300
|
+
*
|
|
301
|
+
* If you were looking for Lit's `@queryAll` decorator, use this as a getter
|
|
302
|
+
* instead, as in the example below.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* class MyComponent extends Component {
|
|
306
|
+
* get buttons(): NodeListOf<HTMLButtonElement> {
|
|
307
|
+
* return this.queryAll("button");
|
|
308
|
+
* }
|
|
309
|
+
*
|
|
310
|
+
* protected override render() {
|
|
311
|
+
* return html`
|
|
312
|
+
* <button>I am a button</button>
|
|
313
|
+
* <button>I am also a button</button>
|
|
314
|
+
* `;
|
|
315
|
+
* }
|
|
316
|
+
* }
|
|
317
|
+
*/
|
|
111
318
|
queryAll<El extends keyof HTMLElementTagNameMap>(selector: El): NodeListOf<HTMLElementTagNameMap[El]>;
|
|
112
319
|
queryAll<El extends keyof SVGElementTagNameMap>(selector: El): NodeListOf<SVGElementTagNameMap[El]>;
|
|
113
320
|
queryAll<El extends keyof MathMLElementTagNameMap>(selector: El): NodeListOf<MathMLElementTagNameMap[El]>;
|
|
114
321
|
/** @deprecated */
|
|
115
322
|
queryAll<El extends keyof HTMLElementDeprecatedTagNameMap>(selector: El): NodeListOf<HTMLElementDeprecatedTagNameMap[El]>;
|
|
116
323
|
queryAll(selector: string): NodeListOf<Element>;
|
|
324
|
+
/**
|
|
325
|
+
* Find the elements attached to a given slot on this component, according
|
|
326
|
+
* to the provided {@link QuerySlotOptions}.
|
|
327
|
+
*
|
|
328
|
+
* If you include `reactive: true` in your query, the result will be a
|
|
329
|
+
* signal which updates with the contents of the slot.
|
|
330
|
+
*/
|
|
117
331
|
querySlot(options: QuerySlotOptions & {
|
|
118
332
|
nodes: true;
|
|
119
333
|
reactive: true;
|
|
@@ -152,12 +366,10 @@ export declare abstract class Component extends EmitterElement implements Reacti
|
|
|
152
366
|
querySlot<El extends keyof MathMLElementTagNameMap>(options: QuerySlotOptions & {
|
|
153
367
|
selector: El;
|
|
154
368
|
}): Array<MathMLElementTagNameMap[El]>;
|
|
155
|
-
/** @deprecated */
|
|
156
369
|
querySlot<El extends keyof HTMLElementDeprecatedTagNameMap>(options: QuerySlotOptions & {
|
|
157
370
|
reactive: true;
|
|
158
371
|
selector: El;
|
|
159
372
|
}): Signal.Computed<Array<HTMLElementDeprecatedTagNameMap[El]>>;
|
|
160
|
-
/** @deprecated */
|
|
161
373
|
querySlot<El extends keyof HTMLElementDeprecatedTagNameMap>(options: QuerySlotOptions & {
|
|
162
374
|
selector: El;
|
|
163
375
|
}): Array<HTMLElementDeprecatedTagNameMap[El]>;
|
package/dist/component.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web component base class.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
var _a;
|
|
2
6
|
import { isIterable, isNullish } from "@bodil/core/assert";
|
|
3
7
|
import { DisposableContext, toDisposable } from "@bodil/core/disposable";
|
|
@@ -22,13 +26,31 @@ const finalised = Symbol("finalised");
|
|
|
22
26
|
function processCSSStyleSpec(spec) {
|
|
23
27
|
return getCompatibleStyle(typeof spec === "string" ? unsafeCSS(spec) : spec);
|
|
24
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown when a {@link Component.render} method causes infinite
|
|
31
|
+
* re-renders.
|
|
32
|
+
*/
|
|
25
33
|
export class ComponentUpdateLoopError extends Error {
|
|
26
34
|
constructor(message, options) {
|
|
27
35
|
super(message, options);
|
|
28
36
|
this.name = "ComponentUpdateLoopError";
|
|
29
37
|
}
|
|
30
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Base class for web components.
|
|
41
|
+
*/
|
|
31
42
|
export class Component extends EmitterElement {
|
|
43
|
+
/**
|
|
44
|
+
* Declare the web components this element will be using.
|
|
45
|
+
*
|
|
46
|
+
* This is a convenient place to make sure these web components will be
|
|
47
|
+
* defined when your component is rendered. It has no effect otherwise.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* class MyComponent extends Component {
|
|
51
|
+
* static deps: Deps = [ MySubcomponent, MyOtherSubcomponent ];
|
|
52
|
+
* }
|
|
53
|
+
*/
|
|
32
54
|
static { this.deps = []; }
|
|
33
55
|
static { this.shadowRootOptions = { mode: "open" }; }
|
|
34
56
|
static { this.initialisers = new Set(); }
|
|
@@ -52,25 +74,53 @@ export class Component extends EmitterElement {
|
|
|
52
74
|
#initialised;
|
|
53
75
|
#viewTransitionRequested;
|
|
54
76
|
#ignoreAttributeUpdates;
|
|
77
|
+
/**
|
|
78
|
+
* True if this component had scheduled an update which has not yet started.
|
|
79
|
+
*/
|
|
55
80
|
get isUpdatePending() {
|
|
56
81
|
return this.#isUpdatePending;
|
|
57
82
|
}
|
|
58
83
|
get updateComplete() {
|
|
59
84
|
return this.#updateResult.promise;
|
|
60
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* A {@link Promise} which resolves when this component has completed its
|
|
88
|
+
* first update and considers itself stabilised, according to the
|
|
89
|
+
* {@link Component.stabilise} method.
|
|
90
|
+
*
|
|
91
|
+
* By default, a component considers itself stabilised when all of its
|
|
92
|
+
* children which are also {@link Component}s are reporting as stabilised.
|
|
93
|
+
*/
|
|
61
94
|
get hasStabilised() {
|
|
62
95
|
return this.#stabilised.promise;
|
|
63
96
|
}
|
|
64
|
-
|
|
97
|
+
/**
|
|
98
|
+
* An {@link AbortSignal} which will trigger when this component is
|
|
99
|
+
* disconnected from the DOM.
|
|
100
|
+
*
|
|
101
|
+
* This can be passed along to asynchronous tasks such as {@link fetch}
|
|
102
|
+
* initiated by this component, which will then be aborted automatically if
|
|
103
|
+
* the component is removed from the DOM.
|
|
104
|
+
*/
|
|
65
105
|
get abortSignal() {
|
|
66
106
|
return this.#abortController.signal;
|
|
67
107
|
}
|
|
108
|
+
#abortController;
|
|
109
|
+
/**
|
|
110
|
+
* Register a function which will be executed whenever an instance of this
|
|
111
|
+
* class is constructed.
|
|
112
|
+
*/
|
|
68
113
|
static addInitialiser(init) {
|
|
69
114
|
if (!Object.hasOwn(this, "initialisers")) {
|
|
70
115
|
this.initialisers = new Set();
|
|
71
116
|
}
|
|
72
117
|
this.initialisers.add(init);
|
|
73
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* A list of the attributes this element has declared.
|
|
121
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#responding_to_attribute_changes
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
74
124
|
static get observedAttributes() {
|
|
75
125
|
this.finalise();
|
|
76
126
|
return this.attributeConfig.keys().toArray();
|
|
@@ -106,6 +156,7 @@ export class Component extends EmitterElement {
|
|
|
106
156
|
}
|
|
107
157
|
}
|
|
108
158
|
}
|
|
159
|
+
/** @ignore */
|
|
109
160
|
constructor() {
|
|
110
161
|
super();
|
|
111
162
|
this.renderOptions = { host: this };
|
|
@@ -125,7 +176,7 @@ export class Component extends EmitterElement {
|
|
|
125
176
|
// set up reactive fields, because decorators can't do this themselves
|
|
126
177
|
const fields = this.constructor[Symbol.metadata]?.[reactiveFields] ?? [];
|
|
127
178
|
for (const field of fields) {
|
|
128
|
-
const sig = signalForObject(this, field, () => Signal(undefined, { equals: Object.is }));
|
|
179
|
+
const sig = signalForObject(this, field, () => Signal.from(undefined, { equals: Object.is }));
|
|
129
180
|
Object.defineProperty(this, field, {
|
|
130
181
|
get() {
|
|
131
182
|
return sig.get();
|
|
@@ -160,6 +211,13 @@ export class Component extends EmitterElement {
|
|
|
160
211
|
});
|
|
161
212
|
}
|
|
162
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* This lifecycle callback is called when the component is attached to the
|
|
216
|
+
* DOM.
|
|
217
|
+
*
|
|
218
|
+
* Generally, prefer using methods with @{@link connect} decorators to
|
|
219
|
+
* overriding this method.
|
|
220
|
+
*/
|
|
163
221
|
connectedCallback() {
|
|
164
222
|
this.#connectedContext.dispose();
|
|
165
223
|
this.#controllers.forEach((c) => c.hostConnected?.());
|
|
@@ -185,6 +243,13 @@ export class Component extends EmitterElement {
|
|
|
185
243
|
}));
|
|
186
244
|
this.requestUpdate();
|
|
187
245
|
}
|
|
246
|
+
/**
|
|
247
|
+
* This lifecycle callback is called when the component is removed from the
|
|
248
|
+
* DOM.
|
|
249
|
+
*
|
|
250
|
+
* Generally, prefer using methods with @{@link connect} decorators to
|
|
251
|
+
* overriding this method.
|
|
252
|
+
*/
|
|
188
253
|
disconnectedCallback() {
|
|
189
254
|
if (this.#updateSignal !== undefined) {
|
|
190
255
|
this.#updateSignalWatcher.unwatch(this.#updateSignal);
|
|
@@ -197,6 +262,9 @@ export class Component extends EmitterElement {
|
|
|
197
262
|
this.#controllers.forEach((c) => c.hostDisconnected?.());
|
|
198
263
|
this.#connectedContext.dispose();
|
|
199
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* @internal
|
|
267
|
+
*/
|
|
200
268
|
setAttributeQuietly(name, value) {
|
|
201
269
|
this.#ignoreAttributeUpdates++;
|
|
202
270
|
if (value === null) {
|
|
@@ -207,6 +275,9 @@ export class Component extends EmitterElement {
|
|
|
207
275
|
}
|
|
208
276
|
this.#ignoreAttributeUpdates--;
|
|
209
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* @internal
|
|
280
|
+
*/
|
|
210
281
|
attributeChangedCallback(name, old, valueString) {
|
|
211
282
|
if (this.#ignoreAttributeUpdates > 0 || old === valueString) {
|
|
212
283
|
return;
|
|
@@ -217,6 +288,11 @@ export class Component extends EmitterElement {
|
|
|
217
288
|
this[attrConfig.property] = value;
|
|
218
289
|
}
|
|
219
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* Typedoc does *not* like this type signature. TODO figure out how to
|
|
293
|
+
* document it properly.
|
|
294
|
+
* @ignore
|
|
295
|
+
*/
|
|
220
296
|
$signal(prop) {
|
|
221
297
|
const _value = this[prop];
|
|
222
298
|
return signalForObject(this, prop, () => {
|
|
@@ -232,6 +308,16 @@ export class Component extends EmitterElement {
|
|
|
232
308
|
removeController(controller) {
|
|
233
309
|
this.#controllers.delete(controller);
|
|
234
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Create the component's render root.
|
|
313
|
+
*
|
|
314
|
+
* By default, this creates a {@link ShadowRoot} and attaches it to the
|
|
315
|
+
* component.
|
|
316
|
+
*
|
|
317
|
+
* If you don't want to use a shadow DOM, you can override this method to
|
|
318
|
+
* just `return this`, which causes the component's contents to render as
|
|
319
|
+
* direct children of the component itself.
|
|
320
|
+
*/
|
|
235
321
|
createRenderRoot() {
|
|
236
322
|
const renderRoot = this.shadowRoot ??
|
|
237
323
|
this.attachShadow(this.constructor.shadowRootOptions);
|
|
@@ -239,6 +325,9 @@ export class Component extends EmitterElement {
|
|
|
239
325
|
this.renderOptions.renderBefore ??= renderRoot.firstChild;
|
|
240
326
|
return renderRoot;
|
|
241
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* Ask this component to update itself.
|
|
330
|
+
*/
|
|
242
331
|
requestUpdate(opts) {
|
|
243
332
|
this.#dirty = true;
|
|
244
333
|
if (opts?.viewTransition === true) {
|
|
@@ -250,7 +339,9 @@ export class Component extends EmitterElement {
|
|
|
250
339
|
scheduler(this);
|
|
251
340
|
}
|
|
252
341
|
}
|
|
253
|
-
|
|
342
|
+
/**
|
|
343
|
+
* @internal
|
|
344
|
+
*/
|
|
254
345
|
hasRequiredProperties() {
|
|
255
346
|
if (this.#hasRequiredProperties === undefined) {
|
|
256
347
|
const requiredProperties = this.constructor.requiredProperties;
|
|
@@ -267,6 +358,8 @@ export class Component extends EmitterElement {
|
|
|
267
358
|
}
|
|
268
359
|
return this.#hasRequiredProperties;
|
|
269
360
|
}
|
|
361
|
+
#hasRequiredProperties;
|
|
362
|
+
/** @internal */
|
|
270
363
|
async performUpdate() {
|
|
271
364
|
if (!this.isConnected || !this.isUpdatePending) {
|
|
272
365
|
return;
|
|
@@ -320,6 +413,7 @@ export class Component extends EmitterElement {
|
|
|
320
413
|
}
|
|
321
414
|
}
|
|
322
415
|
}
|
|
416
|
+
/** @internal */
|
|
323
417
|
update() {
|
|
324
418
|
if (this.#updateSignal !== undefined) {
|
|
325
419
|
this.#updateSignalWatcher.unwatch(this.#updateSignal);
|
|
@@ -331,6 +425,10 @@ export class Component extends EmitterElement {
|
|
|
331
425
|
this.#updateSignalWatcher.watch(this.#updateSignal);
|
|
332
426
|
this.#updateSignal.get();
|
|
333
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Return an iterator over this component's children which are also
|
|
430
|
+
* {@link Component}s.
|
|
431
|
+
*/
|
|
334
432
|
findChildComponents(root = this.renderRoot) {
|
|
335
433
|
let all = childElements(root).toArray();
|
|
336
434
|
const top = [...all];
|
|
@@ -339,30 +437,73 @@ export class Component extends EmitterElement {
|
|
|
339
437
|
}
|
|
340
438
|
return Iterator.from(all).filter((el) => el instanceof Component);
|
|
341
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Return a {@link Promise} which resolves when this component considers
|
|
442
|
+
* itself to have stabilised.
|
|
443
|
+
*
|
|
444
|
+
* The default implementation waits for any children which are also
|
|
445
|
+
* {@link Component}s to report that they have also stabilised.
|
|
446
|
+
*/
|
|
342
447
|
async stabilise() {
|
|
343
448
|
// wait for children to stabilise
|
|
344
449
|
const children = this.findChildComponents();
|
|
345
450
|
// eslint-disable-next-line no-console
|
|
346
451
|
await Promise.all(children.map((child) => child.hasStabilised)).catch(console.error);
|
|
347
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* This lifecycle callback is called each time an update has completed.
|
|
455
|
+
*/
|
|
348
456
|
updated() {
|
|
349
|
-
//
|
|
457
|
+
//
|
|
350
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* This lifecycle callback is called after the component's first update has
|
|
461
|
+
* completed, and before {@link Component.updated}.
|
|
462
|
+
*/
|
|
351
463
|
firstUpdated() {
|
|
352
|
-
//
|
|
353
|
-
// {@link Component.updated}.
|
|
464
|
+
//
|
|
354
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* This lifecycle callback is called when the component considers itself
|
|
468
|
+
* stabilised after its first update.
|
|
469
|
+
*
|
|
470
|
+
* @see {@link Component.hasStabilised}
|
|
471
|
+
*/
|
|
355
472
|
stabilised() {
|
|
356
|
-
//
|
|
473
|
+
//
|
|
357
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* This lifecycle callback is called every time a property decorated with
|
|
477
|
+
* the @{@link require} decorator has changed, but only when every property
|
|
478
|
+
* marked as such is not `undefined`.
|
|
479
|
+
*/
|
|
358
480
|
initialised() {
|
|
359
|
-
//
|
|
360
|
-
// such property is non-`undefined`.
|
|
481
|
+
//
|
|
361
482
|
}
|
|
483
|
+
/**
|
|
484
|
+
* This lifecycle callback is called the first time every property decorated
|
|
485
|
+
* with @{@link require} has been defined, and before
|
|
486
|
+
* {@link Component.initialised}.
|
|
487
|
+
*/
|
|
362
488
|
firstInitialised() {
|
|
363
|
-
//
|
|
364
|
-
// defined, and before {@link Component.initialised}.
|
|
489
|
+
//
|
|
365
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Render the component's contents.
|
|
493
|
+
*
|
|
494
|
+
* This function should return a Lit [renderable
|
|
495
|
+
* value](https://lit.dev/docs/templates/expressions/#child-expressions),
|
|
496
|
+
* usually an {@link html} template.
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* class MyComponent extends Component {
|
|
500
|
+
* protected override render() {
|
|
501
|
+
* return html`
|
|
502
|
+
* <h1>Hello Joe!</h1>
|
|
503
|
+
* `;
|
|
504
|
+
* }
|
|
505
|
+
* }
|
|
506
|
+
*/
|
|
366
507
|
render() {
|
|
367
508
|
return nothing;
|
|
368
509
|
}
|
|
@@ -425,9 +566,9 @@ export class Component extends EmitterElement {
|
|
|
425
566
|
return query(slotEl);
|
|
426
567
|
}
|
|
427
568
|
const sig = getOrSetSignal(this, query, () => {
|
|
428
|
-
const sig = Signal(query(slotEl), { equals: listsEqual });
|
|
569
|
+
const sig = Signal.from(query(slotEl), { equals: listsEqual });
|
|
429
570
|
this.addController(new SlotChangeController(this, slot, sig, query));
|
|
430
|
-
return sig.readOnly
|
|
571
|
+
return sig.readOnly;
|
|
431
572
|
});
|
|
432
573
|
return sig;
|
|
433
574
|
}
|