@bodil/dom 0.1.9 → 0.2.0

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.
Files changed (65) hide show
  1. package/dist/component.d.ts +227 -9
  2. package/dist/component.js +185 -38
  3. package/dist/component.js.map +1 -1
  4. package/dist/css.d.ts +4 -0
  5. package/dist/css.js +4 -0
  6. package/dist/css.js.map +1 -1
  7. package/dist/decorators/attribute.d.ts +15 -15
  8. package/dist/decorators/attribute.js +28 -9
  9. package/dist/decorators/attribute.js.map +1 -1
  10. package/dist/decorators/attribute.test.js +58 -6
  11. package/dist/decorators/attribute.test.js.map +1 -1
  12. package/dist/decorators/connect.d.ts +2 -0
  13. package/dist/decorators/connect.js.map +1 -1
  14. package/dist/decorators/connect.test.js +1 -1
  15. package/dist/decorators/connect.test.js.map +1 -1
  16. package/dist/decorators/reactive.d.ts +1 -1
  17. package/dist/decorators/reactive.js +1 -1
  18. package/dist/decorators/reactive.js.map +1 -1
  19. package/dist/decorators/reactive.test.js +1 -1
  20. package/dist/decorators/reactive.test.js.map +1 -1
  21. package/dist/decorators/require.test.js +1 -1
  22. package/dist/decorators/require.test.js.map +1 -1
  23. package/dist/dom.d.ts +43 -1
  24. package/dist/dom.js +63 -15
  25. package/dist/dom.js.map +1 -1
  26. package/dist/dom.test.d.ts +1 -0
  27. package/dist/dom.test.js +20 -0
  28. package/dist/dom.test.js.map +1 -0
  29. package/dist/emitter.d.ts +8 -0
  30. package/dist/emitter.js.map +1 -1
  31. package/dist/event.d.ts +4 -0
  32. package/dist/event.js.map +1 -1
  33. package/dist/geometry.d.ts +7 -0
  34. package/dist/geometry.js +4 -0
  35. package/dist/geometry.js.map +1 -1
  36. package/dist/index.d.ts +2 -1
  37. package/dist/index.js +2 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/signal.d.ts +12 -3
  40. package/dist/signal.js +7 -1
  41. package/dist/signal.js.map +1 -1
  42. package/dist/signal.test.js +2 -2
  43. package/dist/signal.test.js.map +1 -1
  44. package/dist/test.d.ts +17 -0
  45. package/dist/test.js +34 -0
  46. package/dist/test.js.map +1 -0
  47. package/package.json +27 -19
  48. package/src/component.ts +289 -53
  49. package/src/css.ts +5 -0
  50. package/src/decorators/attribute.test.ts +41 -14
  51. package/src/decorators/attribute.ts +57 -29
  52. package/src/decorators/reactive.test.ts +1 -1
  53. package/src/decorators/reactive.ts +4 -4
  54. package/src/decorators/require.test.ts +1 -1
  55. package/src/dom.test.ts +23 -0
  56. package/src/dom.ts +87 -15
  57. package/src/emitter.ts +8 -0
  58. package/src/event.ts +4 -0
  59. package/src/geometry.ts +8 -0
  60. package/src/index.ts +2 -1
  61. package/src/signal.test.ts +2 -2
  62. package/src/signal.ts +13 -2
  63. package/src/test.ts +38 -0
  64. package/src/decorators/connect.test.ts +0 -119
  65. package/src/decorators/connect.ts +0 -85
@@ -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";
@@ -7,7 +11,6 @@ import { EmitterElement } from "./emitter";
7
11
  import { type QuerySlotOptions } from "./slot";
8
12
  export type { ReactiveController, ReactiveControllerHost } from "lit";
9
13
  export { attribute, attributeGetter, attributeSetter, type AttributeOptions, type AttributeGetterSetterOptions, type AttributeType, } from "./decorators/attribute";
10
- export { connect, connectEffect, type ConnectFunction, type ConnectFunctionReturnValue, } from "./decorators/connect";
11
14
  export { reactive } from "./decorators/reactive";
12
15
  export { require } from "./decorators/require";
13
16
  export { EmitterElement } from "./emitter";
@@ -17,19 +20,56 @@ export type UpdateConfig = {
17
20
  viewTransition?: boolean;
18
21
  };
19
22
  declare const finalised: unique symbol;
23
+ export type Disposables = Disposifiable | Iterable<Disposifiable | undefined> | undefined | void;
20
24
  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: Set<() => void>;
72
+ private static initialisers;
33
73
  /** @ignore */
34
74
  protected static attributeConfig: Map<string, AttributeConfig>;
35
75
  /** @ignore */
@@ -40,35 +80,162 @@ 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
- static addInitialiser(init: () => void): void;
48
- static get observedAttributes(): Array<string>;
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();
51
- protected connectedCallback(): void;
52
- protected disconnectedCallback(): void;
120
+ private connectedCallback;
121
+ private disconnectedCallback;
122
+ /**
123
+ * @internal
124
+ */
53
125
  setAttributeQuietly(name: string, value: string | null): void;
126
+ /**
127
+ * @internal
128
+ */
54
129
  protected attributeChangedCallback(name: string, old: string | null, valueString: string | null): void;
55
- $signal<K extends keyof this & string, V extends this[K]>(prop: K): Signal<V>;
130
+ /**
131
+ * Typedoc does *not* like this type signature. TODO figure out how to
132
+ * document it properly.
133
+ * @ignore
134
+ */
135
+ $signal<K extends keyof this & string, V extends this[K]>(prop: K): Signal.Computed<V>;
56
136
  addController(controller: ReactiveController): void;
57
137
  removeController(controller: ReactiveController): void;
138
+ /**
139
+ * Create the component's render root.
140
+ *
141
+ * By default, this creates a {@link ShadowRoot} and attaches it to the
142
+ * component.
143
+ *
144
+ * If you don't want to use a shadow DOM, you can override this method to
145
+ * just `return this`, which causes the component's contents to render as
146
+ * direct children of the component itself.
147
+ */
58
148
  protected createRenderRoot(): HTMLElement | ShadowRoot;
149
+ /**
150
+ * Ask this component to update itself.
151
+ */
59
152
  requestUpdate(opts?: UpdateConfig): void;
153
+ /**
154
+ * @internal
155
+ */
60
156
  hasRequiredProperties(): Signal.Computed<boolean>;
157
+ /** @internal */
61
158
  protected performUpdate(): Promise<void>;
159
+ /** @internal */
62
160
  protected update(): void;
161
+ /**
162
+ * Return an iterator over this component's children which are also
163
+ * {@link Component}s.
164
+ */
63
165
  protected findChildComponents(root?: Element | ShadowRoot): IteratorObject<Component>;
166
+ /**
167
+ * Return a {@link Promise} which resolves when this component considers
168
+ * itself to have stabilised.
169
+ *
170
+ * The default implementation waits for any children which are also
171
+ * {@link Component}s to report that they have also stabilised.
172
+ */
64
173
  protected stabilise(): Promise<void>;
174
+ /**
175
+ * This lifecycle callback is called each time this component is connected
176
+ * to the DOM.
177
+ */
178
+ protected connected(): void;
179
+ /**
180
+ * This lifecycle callback is called each time this component is
181
+ * disconnected from the DOM.
182
+ */
183
+ protected disconnected(): void;
184
+ /**
185
+ * This lifecycle callback is called each time an update has completed.
186
+ */
65
187
  protected updated(): void;
188
+ /**
189
+ * This lifecycle callback is called after the component's first update has
190
+ * completed, and before {@link Component.updated}.
191
+ */
66
192
  protected firstUpdated(): void;
193
+ /**
194
+ * This lifecycle callback is called when the component considers itself
195
+ * stabilised after its first update.
196
+ *
197
+ * @see {@link Component.hasStabilised}
198
+ */
67
199
  protected stabilised(): void;
200
+ /**
201
+ * This lifecycle callback is called every time a property decorated with
202
+ * the @{@link require} decorator has changed, but only when every property
203
+ * marked as such is not `undefined`.
204
+ */
68
205
  protected initialised(): void;
206
+ /**
207
+ * This lifecycle callback is called the first time every property decorated
208
+ * with @{@link require} has been defined, and before
209
+ * {@link Component.initialised}.
210
+ */
69
211
  protected firstInitialised(): void;
212
+ /**
213
+ * Render the component's contents.
214
+ *
215
+ * This function should return a Lit [renderable
216
+ * value](https://lit.dev/docs/templates/expressions/#child-expressions),
217
+ * usually an {@link html} template.
218
+ *
219
+ * @example
220
+ * class MyComponent extends Component {
221
+ * protected override render() {
222
+ * return html`
223
+ * <h1>Hello Joe!</h1>
224
+ * `;
225
+ * }
226
+ * }
227
+ */
70
228
  protected render(): unknown;
71
229
  [Symbol.dispose](): void;
230
+ /**
231
+ * Register a {@link Disposable} for automatic disposal when this component
232
+ * is disposed.
233
+ */
234
+ use(disposifiable: undefined): undefined;
235
+ use(disposifiable: null): null;
236
+ use(disposifiable: Disposifiable): Disposable;
237
+ use(disposifiable: Disposifiable | undefined): Disposable | undefined;
238
+ use(disposifiable: Disposifiable | null | undefined): Disposable | null | undefined;
72
239
  /**
73
240
  * Attach a {@link Disposable} to the component's connected/disconnected
74
241
  * lifecycle state.
@@ -85,6 +252,7 @@ export declare abstract class Component extends EmitterElement implements Reacti
85
252
  * this.useWhileConnected(this.on("click", this.handleClick.bind(this)));
86
253
  * }
87
254
  */
255
+ useWhileConnected(disposifiable: Disposifiable, secondDisposable: Disposifiable, ...disposifiables: Array<Disposifiable>): Array<Disposable>;
88
256
  useWhileConnected(disposifiable: undefined): undefined;
89
257
  useWhileConnected(disposifiable: null): null;
90
258
  useWhileConnected(disposifiable: Disposifiable): Disposable;
@@ -102,18 +270,70 @@ export declare abstract class Component extends EmitterElement implements Reacti
102
270
  * element. Otherwise, return null.
103
271
  */
104
272
  getFocusedElement(): Element | null;
273
+ /**
274
+ * Find the first element in the component's {@link Component.renderRoot}
275
+ * matching the provided CSS selector.
276
+ *
277
+ * If you need to query the component's direct child elements instead, use
278
+ * {@link Component.querySlot}.
279
+ *
280
+ * If you were looking for Lit's `@query` decorator, use this as a getter
281
+ * instead, as in the example below.
282
+ *
283
+ * @example
284
+ * class MyComponent extends Component {
285
+ * get button(): HTMLButtonElement {
286
+ * return this.query("button");
287
+ * }
288
+ *
289
+ * protected override render() {
290
+ * return html`<button>I am a button</button>`;
291
+ * }
292
+ * }
293
+ */
105
294
  query<El extends keyof HTMLElementTagNameMap>(selector: El): HTMLElementTagNameMap[El] | null;
106
295
  query<El extends keyof SVGElementTagNameMap>(selector: El): SVGElementTagNameMap[El] | null;
107
296
  query<El extends keyof MathMLElementTagNameMap>(selector: El): MathMLElementTagNameMap[El] | null;
108
297
  /** @deprecated */
109
298
  query<El extends keyof HTMLElementDeprecatedTagNameMap>(selector: El): HTMLElementDeprecatedTagNameMap[El] | null;
110
299
  query(selector: string): Element | null;
300
+ /**
301
+ * Find all elements in the component's {@link Component.renderRoot}
302
+ * matching the provided CSS selector.
303
+ *
304
+ * If you need to query the component's direct child elements instead, use
305
+ * {@link Component.querySlot}.
306
+ *
307
+ * If you were looking for Lit's `@queryAll` decorator, use this as a getter
308
+ * instead, as in the example below.
309
+ *
310
+ * @example
311
+ * class MyComponent extends Component {
312
+ * get buttons(): NodeListOf<HTMLButtonElement> {
313
+ * return this.queryAll("button");
314
+ * }
315
+ *
316
+ * protected override render() {
317
+ * return html`
318
+ * <button>I am a button</button>
319
+ * <button>I am also a button</button>
320
+ * `;
321
+ * }
322
+ * }
323
+ */
111
324
  queryAll<El extends keyof HTMLElementTagNameMap>(selector: El): NodeListOf<HTMLElementTagNameMap[El]>;
112
325
  queryAll<El extends keyof SVGElementTagNameMap>(selector: El): NodeListOf<SVGElementTagNameMap[El]>;
113
326
  queryAll<El extends keyof MathMLElementTagNameMap>(selector: El): NodeListOf<MathMLElementTagNameMap[El]>;
114
327
  /** @deprecated */
115
328
  queryAll<El extends keyof HTMLElementDeprecatedTagNameMap>(selector: El): NodeListOf<HTMLElementDeprecatedTagNameMap[El]>;
116
329
  queryAll(selector: string): NodeListOf<Element>;
330
+ /**
331
+ * Find the elements attached to a given slot on this component, according
332
+ * to the provided {@link QuerySlotOptions}.
333
+ *
334
+ * If you include `reactive: true` in your query, the result will be a
335
+ * signal which updates with the contents of the slot.
336
+ */
117
337
  querySlot(options: QuerySlotOptions & {
118
338
  nodes: true;
119
339
  reactive: true;
@@ -152,12 +372,10 @@ export declare abstract class Component extends EmitterElement implements Reacti
152
372
  querySlot<El extends keyof MathMLElementTagNameMap>(options: QuerySlotOptions & {
153
373
  selector: El;
154
374
  }): Array<MathMLElementTagNameMap[El]>;
155
- /** @deprecated */
156
375
  querySlot<El extends keyof HTMLElementDeprecatedTagNameMap>(options: QuerySlotOptions & {
157
376
  reactive: true;
158
377
  selector: El;
159
378
  }): Signal.Computed<Array<HTMLElementDeprecatedTagNameMap[El]>>;
160
- /** @deprecated */
161
379
  querySlot<El extends keyof HTMLElementDeprecatedTagNameMap>(options: QuerySlotOptions & {
162
380
  selector: El;
163
381
  }): Array<HTMLElementDeprecatedTagNameMap[El]>;