@rusticarcade/palette 0.3.1 → 0.7.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.
@@ -13,30 +13,15 @@ type StateListener<Shape> = (state: Shape) => void;
13
13
  *
14
14
  * The State class wraps stateful data and provides an API for mutating the data
15
15
  * while listeners subscribe to meaningful updates.
16
- *
17
- * Modify state with setters, mutators, transactions, or proxied updates with
18
- * deep reactivity and array mutation support built in.
19
- *
20
- * @example
21
- *
22
- * ```typescript
23
- * const state = new State({count: 1});
24
- * state.addListener(data => console.log(data))
25
- *
26
- * state.set("count", 2); // Prints "2"
27
- * state.set("count", 2); // Nothing happens, no change
28
- * state.live.count = 3; // Prints "3"
29
- * ```
30
16
  */
31
17
  declare class State<Shape extends object> {
18
+ static isState<T extends object>(value: unknown): value is State<T>;
32
19
  private _data;
33
20
  private _listeners;
34
21
  private _proxy?;
35
22
  private _proxyCache;
36
23
  private _reverseProxyCache;
37
- private _isLocked;
38
- private _hasWarned;
39
- constructor(initialData: Shape, onChange?: StateListener<Shape>);
24
+ constructor(initialData: Shape, listener?: StateListener<Shape>);
40
25
  /**
41
26
  * Lazily create and cache proxies into the state for reactive updates on
42
27
  * nested values.
@@ -66,37 +51,17 @@ declare class State<Shape extends object> {
66
51
  * This is a direct reference to the internal state. It is marked as Readonly
67
52
  * to help prevent accidental changes. Never edit this value directly.
68
53
  */
69
- get current(): Readonly<Shape>;
54
+ get raw(): Readonly<Shape>;
70
55
  /**
71
- * Proxied access to state properties with automatic reconciliation.
72
- *
73
- * Allows direct property access for both reading and writing state values.
74
- *
75
- * @example
76
- *
77
- * Deep reactivity with the `.live` accessor
78
- *
79
- * ```typescript
80
- * const state = new State({
81
- * nested: {
82
- * values: [1, 2, 3],
83
- * }
84
- * });
85
- *
86
- * // Deep value assignment triggers state updates
87
- * state.live.nested.values[1] = 5;
56
+ * Live reactive accessor for state data. Deeply nested changes trigger
57
+ * automatic updates, including array, Map, and Set mutations.
88
58
  *
89
- * // Array mutators are automatically reactive as well
90
- * state.live.nested.values.push(4);
91
- * state.live.nested.values.reverse();
92
- * ```
59
+ * @remarks
60
+ * For deeply nested values, the `.live` accessor may add performance overhead
61
+ * compared to directly accessing the value via `.current`
93
62
  */
94
63
  get live(): Shape;
95
64
  /**
96
- * Indicates if this state is currently locked (true) or not (false)
97
- */
98
- get isLocked(): boolean;
99
- /**
100
65
  * Add a handler function for when this state changes.
101
66
  *
102
67
  * Listeners are invoked in the order they are registered and are passed a
@@ -115,14 +80,6 @@ declare class State<Shape extends object> {
115
80
  *
116
81
  * The value is returned as Readonly to prevent accidental state mutations.
117
82
  * To mutate stateful properties, use {@link set} or {@link patch} instead.
118
- *
119
- * @example
120
- *
121
- * ```typescript
122
- * const state = new State({ count: 1 });
123
- * console.log(state.get("count")); // 1
124
- * ```
125
- *
126
83
  */
127
84
  get: <K extends keyof Shape>(key: K) => Readonly<Shape[K]>;
128
85
  /**
@@ -131,13 +88,6 @@ declare class State<Shape extends object> {
131
88
  *
132
89
  * The object returned from this function can be edited without modifying the
133
90
  * actual internal state.
134
- *
135
- * @example
136
- *
137
- * ```typescript
138
- * const snap = state.snapshot();
139
- * snap.count += 1;
140
- * state.patch(snap);
141
91
  * ```
142
92
  */
143
93
  snapshot: () => Shape;
@@ -154,44 +104,17 @@ declare class State<Shape extends object> {
154
104
  * state.set("count", 2); // State is now { count: 2, color: "red" }
155
105
  * ```
156
106
  */
157
- set: <K extends keyof Shape>(key: K, value: Shape[K]) => void;
107
+ set: <K extends keyof Shape>(key: K, value: Shape[K]) => State<Shape>;
158
108
  /**
159
109
  * Set multiple stateful properties at once, leaving omitted properties
160
110
  * unchanged.
161
- *
162
- * @example
163
- *
164
- * Patch a partial state, updating all listed properties at once
165
- *
166
- * ```typescript
167
- * const state = new State({
168
- * weather: "sunny",
169
- * temperature: 30,
170
- * humidity: 70,
171
- * });
172
- *
173
- * // Leaves `temperature` unchanged
174
- * state.patch({
175
- * weather: "cloudy",
176
- * humidity: 50,
177
- * });
178
- * ```
179
111
  */
180
112
  patch: (patch: Partial<Shape>) => State<Shape>;
181
113
  /**
182
- * Fully replace the current state data and force listeners to receive the
183
- * updated data immediately.
114
+ * Fully replace the current state data and force an update
184
115
  */
185
116
  replace: (state: Shape) => State<Shape>;
186
117
  /**
187
- * Lock this State instance, preventing further external changes
188
- */
189
- lock: () => State<Shape>;
190
- /**
191
- * Unlock this State instance, allowing further external changes
192
- */
193
- unlock: () => State<Shape>;
194
- /**
195
118
  * Apply complex updates to the state using a mutator function.
196
119
  *
197
120
  * The mutator function takes one parameter which is a structuredClone copy of
@@ -199,87 +122,79 @@ declare class State<Shape extends object> {
199
122
  * patched in to the state.
200
123
  */
201
124
  mutate: (mutator: (current: Shape) => Shape) => State<Shape>;
202
- /**
203
- * Perform an async mutation of the state, optionally locking the state during
204
- * the process.
205
- * @param mutator A function to mutate and return the new state
206
- * @param lock If `true`, lock the state until the mutator completes
207
- */
208
- mutateAsync: (mutator: (current: Shape) => Promise<Shape>, lock?: boolean) => Promise<State<Shape>>;
209
- /**
210
- * Perform a transaction-style set of actions defined within a function.
211
- *
212
- * The provided function can do anything, beyond just setting state. Any
213
- * uncaught errors thrown from within the function will cause the transaction
214
- * to fail and the state to automatically roll back to the last valid state.
215
- *
216
- * During a transaction, this state instance will be locked, preventing other
217
- * changes.
218
- *
219
- * Transactions will always result in a state update when successful.
220
- *
221
- * @example
222
- *
223
- * Transactions with locking and rollback support
224
- *
225
- * ```typescript
226
- * const state = new State({count: 1});
227
- *
228
- * state.transaction(async (s) => {
229
- * // `s` is a full State object you can safely manipulate
230
- * s.set("count", 10);
231
- * });
232
- * state.get("count"); // => 10;
233
- *
234
- * // Errors inside the transaction roll back the state
235
- * state.transaction(async (s) => {
236
- * s.set("count", 100);
237
- * throw new Error();
238
- * });
239
- * state.get("count"); // => 10;
240
- */
241
- transaction: (fn: (state: State<Shape>) => void) => boolean;
242
- /**
243
- * Perform a transaction-style set of actions defined within an async function
244
- *
245
- * The provided function can do anything, beyond just setting state. Any
246
- * uncaught errors thrown from within the function will cause the transaction
247
- * to fail and the state to automatically roll back to the last valid state.
248
- *
249
- * During a transaction, this state instance will be locked, preventing other
250
- * changes.
251
- *
252
- * Transactions will always result in a state update when successful.
253
- *
254
- * @example
255
- *
256
- * Transactions with locking and rollback support
257
- *
258
- * ```typescript
259
- * const state = new State({count: 1});
260
- *
261
- * // Awaiting the result of a transaction
262
- * await state.transactionAsync(async (s) => {
263
- * // `s` is a full State object you can safely manipulate
264
- * s.set("count", 10);
265
- * });
266
- * state.get("count"); // => 10;
267
- *
268
- * // Errors inside the transaction roll back the state
269
- * await state.transactionAsync(async (s) => {
270
- * s.set("count", 100);
271
- * throw new Error();
272
- * });
273
- * state.get("count"); // => 10;
274
- *
275
- * // If you forget to await the transaction, its still locked
276
- * state.transactionAsync(async (s) => {
277
- * await waitSeconds(1);
278
- * });
279
- * state.set("count", 1); // Error: State is locked!
280
- * ```
281
- */
282
- transactionAsync: (fn: (state: State<Shape>) => Promise<void>) => Promise<boolean>;
125
+ }
126
+ type ParsedNotation = {
127
+ /** The raw string representation of the parsed notation */
128
+ base: string;
129
+ /** An array of property names forming a path to the notation value */
130
+ path: string[];
131
+ modifiers?: {
132
+ not?: boolean;
133
+ };
134
+ };
135
+ type NotationAccessor = (source: unknown) => unknown;
136
+ declare const enum Directive {
137
+ Each = "::each",
138
+ Key = "::key",
139
+ Tag = "::tag",
140
+ Swap = "::swap",
141
+ If = "::if",
142
+ ElseIf = "::else-if",
143
+ Else = "::else"
144
+ }
145
+ declare const enum UpdateType {
146
+ Conditional = "cond",
147
+ Tag = "tag",
148
+ Attribute = "attr",
149
+ List = "list",
150
+ Swap = "swap"
151
+ }
152
+ type ConditionalRenderSchemeBranch = {
153
+ type: Directive.If | Directive.ElseIf;
154
+ notation: ParsedNotation;
155
+ branchRootRef: string;
156
+ branchTemplateHTML: string;
157
+ } | {
158
+ type: Directive.Else;
159
+ branchRootRef: string;
160
+ branchTemplateHTML: string;
161
+ };
162
+ interface ConditionalRenderScheme {
163
+ type: UpdateType.Conditional;
164
+ branches: ConditionalRenderSchemeBranch[];
165
+ }
166
+ interface AttributeUpdateScheme {
167
+ type: UpdateType.Attribute;
168
+ notation: ParsedNotation;
169
+ attribute: string;
170
+ nodeRef: string;
171
+ }
172
+ interface TagChangeScheme {
173
+ type: UpdateType.Tag;
174
+ notation: ParsedNotation;
175
+ nodeRef: string;
176
+ }
177
+ interface ContentSwapScheme {
178
+ type: UpdateType.Swap;
179
+ notation: ParsedNotation;
180
+ nodeRef: string;
181
+ }
182
+ interface ListRenderScheme {
183
+ type: UpdateType.List;
184
+ notation: ParsedNotation;
185
+ keyNotation: ParsedNotation;
186
+ nodeRef: string;
187
+ listContentHtml: string;
188
+ }
189
+ type AnyScheme = AttributeUpdateScheme | TagChangeScheme | ContentSwapScheme | ListRenderScheme | ConditionalRenderScheme;
190
+ /**
191
+ * A JSON-serializable representation of a {@link Template} instance, including
192
+ * everything needed to recreate the template.
193
+ */
194
+ interface CompiledTemplate {
195
+ html: string;
196
+ schemes: AnyScheme[];
197
+ notations: Record<string, ParsedNotation>;
283
198
  }
284
199
  type TemplateRoot = HTMLElement | ShadowRoot;
285
200
  type TemplateContext = {
@@ -295,20 +210,33 @@ type TemplateContext = {
295
210
  * Leverages a simple syntax to provide accessors to template data from one of
296
211
  * four categories, based on use case:
297
212
  *
298
- * ```
299
- * `@` -> The `attr` namespace (the host element's attributes)
300
- * `$` -> The `state` namespace (the host element's reactive state)
301
- * `*` -> The `data` namespace (the host element's computed data)
302
- * `#` -> The `item` namespace (list item access with ::each)
303
- * ```
213
+ * | Prefix | Namespace |
214
+ * | ------ | ------------------------------------------------ |
215
+ * | `@` | The `attr` namespace (host element attributes) |
216
+ * | `$` | The `state` namespace (component reactive state) |
217
+ * | `*` | The `data` namespace (component computed props) |
218
+ * | `#` | The `item` namespace (list item context) |
304
219
  *
305
220
  * Bind attributes to a value using the `:attribute` syntax:
306
221
  *
307
222
  * ```html
308
223
  * <div :id="$id" :class="@classname"></div>
309
224
  * ```
225
+ *
226
+ * Or use directives with notations for advanced templating:
227
+ *
228
+ * ```html
229
+ * <div ::if="*showList">
230
+ * <ul>
231
+ * <li ::each="$items" ::key="#id">
232
+ * <span ::swap="#content"></span>
233
+ * </li>
234
+ * </ul>
235
+ * </div>
236
+ * ```
310
237
  */
311
238
  declare class Template {
239
+ static isTemplate(value: unknown): value is Template;
312
240
  /**
313
241
  * Properties related to the global Template build cache.
314
242
  *
@@ -355,7 +283,10 @@ declare class Template {
355
283
  private _plansByNotation;
356
284
  /** Value Notations -> Accessor functions */
357
285
  private _notationAccessors;
286
+ private _subtemplates;
358
287
  constructor(template: HTMLTemplateElement);
288
+ get compiled(): CompiledTemplate;
289
+ get notationMap(): Map<string, NotationAccessor>;
359
290
  /**
360
291
  * Create a full copy of this template for use in rendering to another root
361
292
  */
@@ -366,6 +297,7 @@ declare class Template {
366
297
  element: () => HTMLTemplateElement;
367
298
  private _collectUpdatedValues;
368
299
  private _update;
300
+ renderWithValues: (root: TemplateRoot, values: Map<string, unknown>) => void;
369
301
  /**
370
302
  * Render this template into a target host element.
371
303
  */
@@ -373,16 +305,10 @@ declare class Template {
373
305
  }
374
306
  type EventName = keyof GlobalEventHandlersEventMap;
375
307
  type EventHandler<K extends EventName = EventName> = (event: GlobalEventHandlersEventMap[K]) => void;
376
- interface LiveAttributes<State extends object = {}> {
377
- [name: string]: {
378
- onChange?: (this: Component<State>, current: string | null, previous: string | null) => void;
379
- reflect?: (this: Component<State>) => unknown;
380
- };
308
+ declare enum RootMode {
309
+ Closed = "closed",
310
+ Open = "open"
381
311
  }
382
- type ComputedProperties<StateShape extends object = {}> = Record<string, unknown> | ((this: Component<StateShape>) => Record<string, unknown>);
383
- type ComponentStyles = CSSStyleSheet | CSSStyleSheet[] | string;
384
- type AttributeMap = Map<string, string | null>;
385
- type StateInitializer<Shape extends object = {}> = Shape | State<Shape> | ((this: Component<Shape>) => Shape | State<Shape>);
386
312
  /**
387
313
  * The **Component** class extends the base HTMLElement class to provide an
388
314
  * ergonomic way to design and develop Web Components with reactive state,
@@ -390,181 +316,56 @@ type StateInitializer<Shape extends object = {}> = Shape | State<Shape> | ((this
390
316
  */
391
317
  declare abstract class Component<StateShape extends object = {}> extends HTMLElement {
392
318
  /**
393
- * Register a Component with the browser. Optionally provide an overriding
394
- * tag name.
319
+ * Check if a value is a Component instance
395
320
  */
396
- static register(component: CustomElementConstructor | typeof Component, tagName?: string): void;
321
+ static isComponent(value: unknown): value is Component;
397
322
  /**
398
- * The HTML tag name to use for this Component
323
+ * Check if a value is a Component class
399
324
  */
325
+ static isComponentClass(value: unknown): value is typeof Component;
326
+ static readComponentTagName(componentClass: typeof Component): string;
327
+ /** The HTML tag name to use for this Component */
400
328
  static tagName: string;
401
- /**
402
- * An HTML Template element for this element to use.
403
- */
329
+ /** An HTML Template element for this element to use. */
404
330
  static template: HTMLTemplateElement | Template;
405
- /**
406
- * A {@link CSSStyleSheet} array or string to adopt as the component's scoped styles
407
- */
408
- static styles: ComponentStyles;
409
- /**
410
- * An array of html attribute names to observe to trigger updates.
411
- *
412
- * @remarks
413
- * If you use the {@link define} factory helper, this value will be
414
- * automatically merged with a list of any defined {@link liveAttributes}.
415
- */
331
+ /** Styles to encapsulate to this component's root. */
332
+ static style: CSSStyleSheet | CSSStyleSheet[] | string;
333
+ /** Attributes to watch for changes for updates. */
416
334
  static observedAttributes: string[];
417
335
  /**
418
336
  * The mode for this Component's ShadowRoot.
419
337
  *
420
- * - `"open"` allows JS access to the children of this component
421
- * - `"closed"` (default) disallows internal JS access
422
- */
423
- static shadowRootMode: "closed" | "open";
424
- /**
425
- * Called immediately before each template update
338
+ * MDN: https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/mode
426
339
  */
427
- protected beforeUpdate?(): void;
340
+ static rootMode: RootMode;
341
+ /** Called immediately before each template update */
342
+ beforeUpdate?(changedAttributes: Record<string, string | null>): void;
343
+ /** Called immediately after each template update */
344
+ afterUpdate?(previousAttributes: Record<string, string | null>): void;
345
+ /** Final lifecycle method called at the end of the unmounting process. */
346
+ finalize?(): void;
428
347
  /**
429
- * Called immediately after each template update
430
- */
431
- protected afterUpdate?(previousAttributes: AttributeMap): void;
432
- /**
433
- * Called as the final lifecycle method at the end of the unmounting process.
434
- *
435
- * Content has been removed from the DOM and the component is no longer
436
- * considered mounted when this function runs.
437
- *
438
- * Use this for final cleanup tasks and freeing resources.
348
+ * Handle errors thrown during lifecycle methods of this component or any
349
+ * unhandled errors from child components.
439
350
  */
440
- protected finalize?(): void;
441
- /**
442
- * If defined, receives errors caught during the lifecycle methods of this
443
- * component and it's children. If not defined, this component will instead
444
- * throw errors as they are found.
445
- *
446
- * If the error cannot be handled, `onError()` should re-throw it for a higher
447
- * up component to evaluate.
448
- *
449
- * To display an error message while removing an erroring component from the
450
- * DOM, use `this.replaceWith()` and a newly constructed placeholder element.
451
- *
452
- * @example
453
- *
454
- * Recovering from errors or displaying a fallback
455
- *
456
- * ```typescript
457
- * onError(error) {
458
- * // Handle known errors
459
- * if (error.message = "Invalid Input") {
460
- * this.state.input = "";
461
- * return;
462
- * }
463
- *
464
- * // Display a fallback banner
465
- * const banner = document.createElement("div");
466
- * banner.textContent = "An unexpected error done did";
467
- * this.replaceWith(banner);
468
- * }
469
- * ```
470
- */
471
- protected onError?(error: unknown): void;
472
- /**
473
- * The initial value for this Component's reactive internal state, if any.
474
- *
475
- * If `initialState` is defined as a function, the function is evaluated at
476
- * mounting time and the return value is used as the initial state.
477
- */
478
- protected initialState?: StateInitializer<StateShape>;
351
+ onError?(error: unknown): void;
352
+ /** The initial state for this Component */
353
+ initialState?(): State<StateShape> | StateShape;
479
354
  /**
480
355
  * An object or function returning an object which populates the `data` values
481
356
  * in the templating engine. Such values are accessed using the `*` notation.
482
- *
483
- * When a hosted value is accessed, it's value is coerced based on the way it
484
- * is being used. For attributes, values are serialized to a string or null,
485
- * which will set the attribute (string) or remove it (null).
486
- *
487
- * For content swaps, strings, numbers and booleans are rendered as strings
488
- * and set as textContent. null and undefined values render nothing (with a
489
- * comment placeholder), an HTMLElement will be swapped in as a cloned node.
490
- *
491
- * Functions are evaluated at render/update time, and their return value is
492
- * used instead. Functions are passed the current target node accessing the
493
- * property as its first and only argument.
494
- *
495
- * Other types are unsupported.
496
- *
497
- * @example
498
- *
499
- * ```typescript
500
- * host = {
501
- * avatarUrl: "http://...",
502
- * renderTime: () => new Date().toISOString(),
503
- * }
504
- * ```
505
- *
506
- * ```html
507
- * <img :src="*avatarUrl" />
508
- * <span>Rendered at ${"*renderTime"}</span>
509
- * ```
510
357
  */
511
- protected computedProperties?: ComputedProperties<StateShape>;
512
- /**
513
- * Declaration of attribute behaviors during updates.
514
- *
515
- * Each key is the name of an attribute. Values are an object with two
516
- * optional function definitions:
517
- *
518
- * `onChange(newValue, oldValue): void`, a handler function for when the value
519
- * of this attribute has changed. Runs once per update cycle, *before* the
520
- * update occurs.
521
- *
522
- * `reflect(): unknown`, a function which returns a value to serialize and set
523
- * as this attribute *after* an update completes.
524
- *
525
- * @example
526
- *
527
- * ```typescript
528
- * liveAttributes = {
529
- * done: {
530
- * onChange(newValue) {
531
- * this.state.set("done", !!newValue);
532
- * },
533
- * reflect() { return this.state.current.done }
534
- * }
535
- * };
536
- * ```
537
- *
538
- * @remarks
539
- *
540
- * If using the {@link define} helper, the keys of this property are
541
- * automatically merged with any defined {@link observedAttributes}.
542
- *
543
- * If you are directly extending the class, `observedAttributes` must be
544
- * explicitly defined with any attributes that should be monitored, regardless
545
- * of if they're defined here.
546
- */
547
- protected liveAttributes?: LiveAttributes<StateShape>;
548
- private _isComponentMounted;
549
- private _template;
550
- private _root;
551
- private _state?;
552
- private _delegator?;
553
- private _ownListeners;
554
- private _liveAttributeConfigs;
555
- private _cleanupFn?;
556
- private _renderInternals;
358
+ computedProperties?(this: Component<StateShape>, attributes: Record<string, string | null>, state: StateShape): Record<string, unknown>;
359
+ readonly root: ShadowRoot;
360
+ readonly template: Template;
361
+ private _cmp;
557
362
  constructor();
558
363
  /** Produce the data object to pass to the template's render function */
559
364
  private _getRenderContext;
560
365
  private _escalateError;
561
366
  private _reportError;
562
- private _executeAttributeChangeHandlers;
563
- private _reflectLiveAttributes;
564
367
  /** The actual update behavior */
565
- private _performUpdate;
566
- /** Safely request for an update to run on the next frame */
567
- private _scheduleUpdate;
368
+ private _render;
568
369
  private _adoptState;
569
370
  /**
570
371
  * @deprecated Use {@link script} instead
@@ -575,193 +376,113 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
575
376
  */
576
377
  protected disconnectedCallback(): void;
577
378
  /**
578
- * @deprecated Use {@link liveAttributes} instead
379
+ * @deprecated Use {@link beforeUpdate} and {@link afterUpdate} instead
579
380
  */
580
381
  protected attributeChangedCallback(name: string, _: string | null, newValue: string | null): void;
382
+ get isMounted(): boolean;
581
383
  /**
582
- * The ShadowRoot node of this element
384
+ * Access the full {@link State} instance for this Component.
385
+ *
386
+ * @remarks
387
+ * Calling this method on a component which is not using reactive state
388
+ * will result in an error being thrown.
583
389
  */
584
- get root(): ShadowRoot;
390
+ getState(): State<StateShape>;
585
391
  /**
586
- * Directly access and manipulate this Component's reactive state with deep
587
- * reactivity enabled.
588
- *
589
- * @example
590
- *
591
- * ```typescript
592
- * initialState = { values: { count: 1, time: 0 } };
392
+ * Accessor for live reactive state.
593
393
  *
594
- * increment() {
595
- * this.state.values.count = 2;
596
- * }
597
- * ```
598
- *
599
- * @remarks
600
- * This is a shorthand getter for `this.getState().live`
394
+ * For the full state manipulation API, use {@link getState}
601
395
  */
602
396
  get state(): StateShape;
603
397
  /**
604
398
  * Replace the current state with a new value or adopt a whole different State
605
399
  * instance
606
- *
607
- * @example
608
- *
609
- * State replacement
610
- *
611
- * ```typescript
612
- * // Always triggers a render
613
- * this.state = { some: "newState" }
614
- *
615
- * // Adopt a new state instance altogether
616
- * const otherState = new State({some: "newState"});
617
- * this.state = otherState;
618
- *
619
- * // Causes a render
620
- * otherState.set("some", "value");
621
- * ```
622
400
  */
623
401
  set state(newState: StateShape | State<StateShape>);
624
402
  /**
625
- * Access the full {@link State} instance for this Component.
626
- *
627
- * Using this method on a component which is not using reactive state
628
- * will result in an error being thrown.
629
- *
630
- * @example
631
- *
632
- * Retrieve stateful value
633
- *
634
- * ```typescript
635
- * class Example extends Component {
636
- * initialState = { count: 1 };
637
- *
638
- * script() {
639
- * const state = this.getState();
640
- * console.log(`The count is ${state.get("count")}`);
641
- * }
642
- *
643
- * }
644
- * ```
645
- *
646
- * @example
647
- *
648
- * Set a stateful value
649
- *
650
- * ```typescript
651
- * class Example extends Component {
652
- * initialState = { count: 1 };
653
- *
654
- * increment() {
655
- * const state = this.getState();
656
- * const current = state.get("count");
657
- * state.set("count", current + 1);
658
- * }
659
- * }
660
- * ```
661
- */
662
- getState(): State<StateShape>;
663
- /**
664
- * Manually schedule a render to occur
403
+ * Manually schedule a render to occur, optionally providing a callback to
404
+ * invoke after the render completes.
665
405
  *
666
406
  * @remarks
667
- * Calling {@link requestRender} multiple times in the same event loop won't
407
+ * Calling {@link render} multiple times in the same event loop won't
668
408
  * schedule multiple renders. Renders are scheduled to occur on the next
669
409
  * animation frame.
670
410
  */
671
- requestRender(callback?: VoidFunction): void;
411
+ render: () => void;
672
412
  /**
673
- * Create a managed event listener on this Component with an optional query
674
- * filter string to specify which elements to listen to events from.
413
+ * Listen for events on a child element based on the provided query
675
414
  *
676
- * Event handlers set up with `listen()` are automatically cleaned up when
677
- * the component is unmounted.
415
+ * @returns A function which removes the listener when called
678
416
  *
679
- * Handlers are delegated to a single listener per event on the root of the
680
- * Component, which is the closed ShadowRoot by default.
417
+ * @remarks
418
+ * Event listeners created with this method are automatically cleaned up when
419
+ * the component unmounts. You can manually remove the listener during the
420
+ * component's lifecycle by calling the returned function if need be.
421
+ */
422
+ listen<E extends EventName>(target: string, eventName: E, eventHandler: EventHandler<E>): VoidFunction;
423
+ /**
424
+ * Listen for events on a child element based on the provided component's tag
681
425
  *
682
- * @example
426
+ * @returns A function which removes the listener when called
683
427
  *
684
- * Set up an event listener for a click event from a button with ID "submit"
428
+ * @remarks
429
+ * Event listeners created with this method are automatically cleaned up when
430
+ * the component unmounts. You can manually remove the listener during the
431
+ * component's lifecycle by calling the returned function if need be.
432
+ */
433
+ listen<E extends EventName>(target: typeof Component<any>, eventName: E, eventHandler: EventHandler<E>): VoidFunction;
434
+ /**
435
+ * Listen for events on the host element
685
436
  *
686
- * ```typescript
687
- * this.listen("#submit", "click", this.handleClick);
688
- * ```
437
+ * @returns A function which removes the listener when called
689
438
  *
690
- * @example
439
+ * @remarks
440
+ * Event listeners created with this method are automatically cleaned up when
441
+ * the component unmounts. You can manually remove the listener during the
442
+ * component's lifecycle by calling the returned function if need be.
443
+ */
444
+ listen<E extends EventName>(target: typeof this, eventName: E, eventHandler: EventHandler<E>): VoidFunction;
445
+ /**
446
+ * Listen for events on the host element
691
447
  *
692
- * Set up an event listener on the host element itself (`this`).
448
+ * @returns A function which removes the listener when called
693
449
  *
694
- * ```typescript
695
- * // Use ":host" or ":HOST" as the query selector to targe the host element
696
- * this.listen(":host", "animationend", this.handler);
697
- * ```
450
+ * @remarks
451
+ * Event listeners created with this method are automatically cleaned up when
452
+ * the component unmounts. You can manually remove the listener during the
453
+ * component's lifecycle by calling the returned function if need be.
698
454
  */
699
- listen<E extends EventName>(targetDescriptor: string | typeof Component<any> | HTMLElement, eventName: E, eventHandler: EventHandler<E>): void;
700
- stopListening<E extends EventName>(targetDescriptor: string | typeof Component<any> | HTMLElement, eventName: E, eventHandler: EventHandler<E>): void;
701
- dispatchEvent(event: Event): boolean;
455
+ listen<E extends EventName>(target: ":host", eventName: E, eventHandler: EventHandler<E>): VoidFunction;
702
456
  /**
703
- * Dispatch a {@link CustomEvent} with the specified name and detail
457
+ * Publish a {@link CustomEvent} with the provided name and options.
704
458
  *
705
- * @example Defining custom events
459
+ * Default options are:
706
460
  *
707
461
  * ```typescript
708
- * // Define types. This can happen in the same file or elsewhere for common
709
- * // and shared events.
710
- * type MyEvent = CustomEvent<T> // Set `T` to the event detail type
711
- *
712
- * declare global {
713
- * interface GlobalEventHandlersEventMap {
714
- * "my-event-name": MyEvent
715
- * }
462
+ * {
463
+ * bubbles: true,
464
+ * cancelable: true,
465
+ * composed: true,
466
+ * detail: undefined,
716
467
  * }
717
- *
718
- * // Dispatch a custom event
719
- * this.dispatchEvent("my-event-name", T);
720
- *
721
- * // Listen to a custom event
722
- * $el.addEventListener("my-event-name", ...);
723
468
  * ```
724
- */
725
- dispatchEvent<T>(event: string, detail?: T, options?: {
726
- bubbles: boolean;
727
- cancelable: boolean;
728
- composed: boolean;
729
- }): boolean;
730
- querySelector<E extends HTMLElement>(query: string): E | null;
731
- querySelectorAll<E extends HTMLElement>(query: string): NodeListOf<E>;
732
- getElementById<E extends HTMLElement>(id: string): E | null;
733
- requireElementById<E extends HTMLElement>(id: string): E;
734
- setAttribute(name: string, value: string): void;
735
- /**
736
- * Set a value as an attribute, serializing to a string or `null`.
737
469
  *
738
- * null values cause the attribute to be removed from this element
470
+ * @param name The name of the custom event to publish
471
+ * @param options Options to configure the custom event
739
472
  */
740
- setAttribute(name: string, value: unknown): void;
741
- getAttribute(name: string): string | null;
473
+ dispatchEvent<T>(name: string, options: CustomEventInit<T>): boolean;
474
+ dispatchEvent(event: Event): boolean;
742
475
  /**
743
- * Get an attribute as a number, falling back to a specified default.
476
+ * Returns a reference to the HTML Element with the provided ID within the
477
+ * shadow root of this component.
744
478
  *
745
- *
746
- * `null` attributes are returned as `null`, while string attributes are
747
- * parsed using the `Number()` constructor.
748
- *
749
- * Values which evaluate to NaN are returned as `null`.
750
- */
751
- getAttribute(name: string, defaultValue: number): number;
752
- /**
753
- * Get an attribute as a string, falling back to a specified default
754
- */
755
- getAttribute(name: string, defaultValue: string): string;
756
- /**
757
- * Set the value of an attribute on this element if the provided value
758
- * differs from the attribute when serialized
479
+ * Throws an error if no element with the provided ID is found
759
480
  */
760
- reflectAttribute(name: string, value: unknown): void;
481
+ ref<E extends HTMLElement>(id: string): E;
761
482
  /**
762
483
  * Serialize this element to a string
763
484
  */
764
- toString(full?: boolean): string;
485
+ toString(): string;
765
486
  }
766
487
  /**
767
488
  * Render a Palette Component class as a test element
@@ -789,7 +510,7 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
789
510
  * @param attributes A record of attributes to apply
790
511
  * @returns A reference to the rendered Component
791
512
  */
792
- declare function renderTestComponent<E extends typeof Component<any>>(component: E, attributes?: Record<string, unknown>): Promise<InstanceType<E>>;
513
+ declare function renderTestComponent<E extends typeof Component<any>>(component: E, attributes?: Record<string, string | null>): Promise<InstanceType<E>>;
793
514
  /**
794
515
  * Force a render on the target element
795
516
  *