@rusticarcade/palette 0.1.0-rc.5

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.
@@ -0,0 +1,922 @@
1
+ type StateListener<Shape> = (state: Shape) => void;
2
+ /**
3
+ * Powerful and flexible state management with deep reactivity, transaction, and
4
+ * locking support.
5
+ *
6
+ * The State class wraps stateful data and provides an API for mutating the data
7
+ * while listeners subscribe to meaningful updates.
8
+ *
9
+ * Modify state with setters, mutators, transactions, or proxied updates with
10
+ * deep reactivity and array mutation support built in.
11
+ *
12
+ * @example
13
+ *
14
+ * ```typescript
15
+ * const state = new State({count: 1});
16
+ * state.addListener(data => console.log(data))
17
+ *
18
+ * state.set("count", 2); // Prints "2"
19
+ * state.set("count", 2); // Nothing happens, no change
20
+ * state.live.count = 3; // Prints "3"
21
+ * ```
22
+ */
23
+ declare class State<Shape extends object> {
24
+ private _data;
25
+ private _listeners;
26
+ private _proxy?;
27
+ private _proxyCache;
28
+ private _reverseProxyCache;
29
+ private _isLocked;
30
+ private _hasWarned;
31
+ constructor(initialData: Shape, onChange?: StateListener<Shape>);
32
+ /**
33
+ * Lazily create and cache proxies into the state for reactive updates on
34
+ * nested values.
35
+ */
36
+ private _createProxy;
37
+ private _unwrapProxy;
38
+ /**
39
+ * Handle setting nested values and emitting updated data if the value changed
40
+ */
41
+ private _setNested;
42
+ /**
43
+ * Process an incoming partial state and emit updates to listeners if there
44
+ * are any changes detected.
45
+ *
46
+ * @remarks
47
+ * Object.is() to check for differences. Does not attempt deep diffing.
48
+ */
49
+ private _processIncomingState;
50
+ /**
51
+ * Emit the current state to all listeners
52
+ */
53
+ private _emit;
54
+ /**
55
+ * The current state
56
+ *
57
+ * @remarks
58
+ * This is a direct reference to the internal state. It is marked as Readonly
59
+ * to help prevent accidental changes. Never edit this value directly.
60
+ */
61
+ get current(): Readonly<Shape>;
62
+ /**
63
+ * Proxied access to state properties with automatic reconciliation.
64
+ *
65
+ * Allows direct property access for both reading and writing state values.
66
+ *
67
+ * @example
68
+ *
69
+ * Deep reactivity with the `.live` accessor
70
+ *
71
+ * ```typescript
72
+ * const state = new State({
73
+ * nested: {
74
+ * values: [1, 2, 3],
75
+ * }
76
+ * });
77
+ *
78
+ * // Deep value assignment triggers state updates
79
+ * state.live.nested.values[1] = 5;
80
+ *
81
+ * // Array mutators are automatically reactive as well
82
+ * state.live.nested.values.push(4);
83
+ * state.live.nested.values.reverse();
84
+ * ```
85
+ */
86
+ get live(): Shape;
87
+ /**
88
+ * Indicates if this state is currently locked (true) or not (false)
89
+ */
90
+ get isLocked(): boolean;
91
+ /**
92
+ * Add a handler function for when this state changes.
93
+ *
94
+ * Listeners are invoked in the order they are registered and are passed a
95
+ * reference to the internally managed state object as a readonly object.
96
+ *
97
+ * **Do not modify state values directly**. Instead, use {@link set} or
98
+ * {@link patch} to make immutable updates.
99
+ */
100
+ addListener: (listener: StateListener<Shape>) => void;
101
+ /**
102
+ * Remove a previously registered state handler
103
+ */
104
+ removeListener: (listener: StateListener<Shape>) => void;
105
+ /**
106
+ * Get a single value from the state object
107
+ *
108
+ * The value is returned as Readonly to prevent accidental state mutations.
109
+ * To mutate stateful properties, use {@link set} or {@link patch} instead.
110
+ *
111
+ * @example
112
+ *
113
+ * ```typescript
114
+ * const state = new State({ count: 1 });
115
+ * console.log(state.get("count")); // 1
116
+ * ```
117
+ *
118
+ */
119
+ get: <K extends keyof Shape>(key: K) => Readonly<Shape[K]>;
120
+ /**
121
+ * Returns a deep clone of the current state data using `structuredClone()` to
122
+ * make the copy.
123
+ *
124
+ * The object returned from this function can be edited without modifying the
125
+ * actual internal state.
126
+ *
127
+ * @example
128
+ *
129
+ * ```typescript
130
+ * const snap = state.snapshot();
131
+ * snap.count += 1;
132
+ * state.patch(snap);
133
+ * ```
134
+ */
135
+ snapshot: () => Shape;
136
+ /**
137
+ * Set a single stateful property while leaving other properties unchanged.
138
+ *
139
+ * Triggers an update to all listeners if the value is different from before
140
+ * when compared using shallow equality.
141
+ *
142
+ * @example
143
+ *
144
+ * ```typescript
145
+ * const state = new State({ count: 1, color: "red" });
146
+ * state.set("count", 2); // State is now { count: 2, color: "red" }
147
+ * ```
148
+ */
149
+ set: <K extends keyof Shape>(key: K, value: Shape[K]) => void;
150
+ /**
151
+ * Set multiple stateful properties at once, leaving omitted properties
152
+ * unchanged.
153
+ *
154
+ * @example
155
+ *
156
+ * Patch a partial state, updating all listed properties at once
157
+ *
158
+ * ```typescript
159
+ * const state = new State({
160
+ * weather: "sunny",
161
+ * temperature: 30,
162
+ * humidity: 70,
163
+ * });
164
+ *
165
+ * // Leaves `temperature` unchanged
166
+ * state.patch({
167
+ * weather: "cloudy",
168
+ * humidity: 50,
169
+ * });
170
+ * ```
171
+ */
172
+ patch: (patch: Partial<Shape>) => State<Shape>;
173
+ /**
174
+ * Fully replace the current state data and force listeners to receive the
175
+ * updated data immediately.
176
+ */
177
+ replace: (state: Shape) => State<Shape>;
178
+ /**
179
+ * Lock this State instance, preventing further external changes
180
+ */
181
+ lock: () => State<Shape>;
182
+ /**
183
+ * Unlock this State instance, allowing further external changes
184
+ */
185
+ unlock: () => State<Shape>;
186
+ /**
187
+ * Apply complex updates to the state using a mutator function.
188
+ *
189
+ * The mutator function takes one parameter which is a structuredClone copy of
190
+ * the current state object. Whatever is returned by the mutator is then
191
+ * patched in to the state.
192
+ */
193
+ mutate: (mutator: (current: Shape) => Shape) => State<Shape>;
194
+ /**
195
+ * Perform an async mutation of the state, optionally locking the state during
196
+ * the process.
197
+ * @param mutator A function to mutate and return the new state
198
+ * @param lock If `true`, lock the state until the mutator completes
199
+ */
200
+ mutateAsync: (mutator: (current: Shape) => Promise<Shape>, lock?: boolean) => Promise<State<Shape>>;
201
+ /**
202
+ * Perform a transaction-style set of actions defined within a function.
203
+ *
204
+ * The provided function can do anything, beyond just setting state. Any
205
+ * uncaught errors thrown from within the function will cause the transaction
206
+ * to fail and the state to automatically roll back to the last valid state.
207
+ *
208
+ * During a transaction, this state instance will be locked, preventing other
209
+ * changes.
210
+ *
211
+ * Transactions will always result in a state update when successful.
212
+ *
213
+ * @example
214
+ *
215
+ * Transactions with locking and rollback support
216
+ *
217
+ * ```typescript
218
+ * const state = new State({count: 1});
219
+ *
220
+ * state.transaction(async (s) => {
221
+ * // `s` is a full State object you can safely manipulate
222
+ * s.set("count", 10);
223
+ * });
224
+ * state.get("count"); // => 10;
225
+ *
226
+ * // Errors inside the transaction roll back the state
227
+ * state.transaction(async (s) => {
228
+ * s.set("count", 100);
229
+ * throw new Error();
230
+ * });
231
+ * state.get("count"); // => 10;
232
+ */
233
+ transaction: (fn: (state: State<Shape>) => void) => boolean;
234
+ /**
235
+ * Perform a transaction-style set of actions defined within an async function
236
+ *
237
+ * The provided function can do anything, beyond just setting state. Any
238
+ * uncaught errors thrown from within the function will cause the transaction
239
+ * to fail and the state to automatically roll back to the last valid state.
240
+ *
241
+ * During a transaction, this state instance will be locked, preventing other
242
+ * changes.
243
+ *
244
+ * Transactions will always result in a state update when successful.
245
+ *
246
+ * @example
247
+ *
248
+ * Transactions with locking and rollback support
249
+ *
250
+ * ```typescript
251
+ * const state = new State({count: 1});
252
+ *
253
+ * // Awaiting the result of a transaction
254
+ * await state.transactionAsync(async (s) => {
255
+ * // `s` is a full State object you can safely manipulate
256
+ * s.set("count", 10);
257
+ * });
258
+ * state.get("count"); // => 10;
259
+ *
260
+ * // Errors inside the transaction roll back the state
261
+ * await state.transactionAsync(async (s) => {
262
+ * s.set("count", 100);
263
+ * throw new Error();
264
+ * });
265
+ * state.get("count"); // => 10;
266
+ *
267
+ * // If you forget to await the transaction, its still locked
268
+ * state.transactionAsync(async (s) => {
269
+ * await waitSeconds(1);
270
+ * });
271
+ * state.set("count", 1); // Error: State is locked!
272
+ * ```
273
+ */
274
+ transactionAsync: (fn: (state: State<Shape>) => Promise<void>) => Promise<boolean>;
275
+ }
276
+ type TemplateRoot = HTMLElement | ShadowRoot;
277
+ type TemplateContext = {
278
+ attr?: Record<string, string | null>;
279
+ state?: Record<string, unknown>;
280
+ data?: Record<string, unknown>;
281
+ item?: Record<string, unknown>;
282
+ index?: number;
283
+ };
284
+ /**
285
+ * A renderable template from an HTMLTemplateElement
286
+ *
287
+ * Leverages a simple syntax to provide accessors to template data from one of
288
+ * four categories, based on use case:
289
+ *
290
+ * ```
291
+ * `@` -> The `attr` namespace (the host element's attributes)
292
+ * `$` -> The `state` namespace (the host element's reactive state)
293
+ * `*` -> The `data` namespace (the host element's computed data)
294
+ * `#` -> The `item` namespace (list item access with ::each)
295
+ * ```
296
+ *
297
+ * Bind attributes to a value using the `:attribute` syntax:
298
+ *
299
+ * ```html
300
+ * <div :id="$id" :class="@classname"></div>
301
+ * ```
302
+ */
303
+ declare class Template {
304
+ /**
305
+ * Properties related to the global Template build cache.
306
+ *
307
+ * This is not something typically needed for general app development, but
308
+ * allows for advanced configuration to tune the caching system if need be.
309
+ *
310
+ * Cache sizes default to 500 HTML Template Fragments and compiled Palette
311
+ * templates (includes nested templates like lists) to cover most application
312
+ * needs without using much memory.
313
+ */
314
+ static cache: {
315
+ /**
316
+ * Wipe all cached templates and HTML fragments
317
+ */
318
+ clear: () => void;
319
+ /**
320
+ * the default cache capacity of 500 items per cache
321
+ *
322
+ * General caching guidance:
323
+ * - 95% of the time, 500 works fine
324
+ * - For very large applications, up to 1000 is reasonable
325
+ * - For smaller apps, dropping down to 100 - 250 may save memory
326
+ *
327
+ * Ultimately the impact will be minimal unless your app has very specific
328
+ * rendering needs.
329
+ */
330
+ setCapacity: (maxSize: number) => void;
331
+ };
332
+ private _compiled;
333
+ /**
334
+ * The original {@link HTMLTemplateElement} used to create this Template.
335
+ *
336
+ * @remarks
337
+ * Make sure to never operate directly on this element. Always clone.
338
+ */
339
+ private _templateElement?;
340
+ /** The current known root element that this Template is rendered into */
341
+ private _mountedRoot?;
342
+ /** The most recent set value for each notation that has rendered */
343
+ private _latestRenderedValues;
344
+ /** The active HTMLElement which the template is updating on renders */
345
+ private _fragment;
346
+ /** Value Notations -> Set<Render Plans> */
347
+ private _plansByNotation;
348
+ /** Value Notations -> Accessor functions */
349
+ private _notationAccessors;
350
+ constructor(template: HTMLTemplateElement);
351
+ /**
352
+ * Create a full copy of this template for use in rendering to another root
353
+ */
354
+ clone: () => Template;
355
+ /**
356
+ * @returns An {@link HTMLTemplateElement} representing this template
357
+ */
358
+ element: () => HTMLTemplateElement;
359
+ private _collectUpdatedValues;
360
+ private _update;
361
+ /**
362
+ * Render this template into a target host element.
363
+ *
364
+ * @remarks
365
+ * If no context is provided, the root element is used as the context, which
366
+ * allows for accessing nested properties of the host element itself.
367
+ */
368
+ render: (root: TemplateRoot, context: TemplateContext) => void;
369
+ }
370
+ type EventName = keyof GlobalEventHandlersEventMap;
371
+ type EventHandler<K extends EventName = EventName> = (event: GlobalEventHandlersEventMap[K]) => void;
372
+ interface LiveAttributes<State extends object = {}> {
373
+ [name: string]: {
374
+ onChange?: (this: Component<State>, current: string | null, previous: string | null) => void;
375
+ reflect?: (this: Component<State>) => unknown;
376
+ };
377
+ }
378
+ type ComputedProperties<StateShape extends object = {}> = Record<string, unknown> | ((this: Component<StateShape>) => Record<string, unknown>);
379
+ type ComponentStyles = CSSStyleSheet | CSSStyleSheet[] | string;
380
+ type AttributeMap = Map<string, string | null>;
381
+ type StateInitializer<Shape extends object = {}> = Shape | State<Shape> | ((this: Component<Shape>) => Shape | State<Shape>);
382
+ /**
383
+ * The **Component** class extends the base HTMLElement class to provide an
384
+ * ergonomic way to design and develop Web Components with reactive state,
385
+ * managed attributes, and dynamic templating.
386
+ */
387
+ declare abstract class Component<StateShape extends object = {}> extends HTMLElement {
388
+ /**
389
+ * Register a Component with the browser. Optionally provide an overriding
390
+ * tag name.
391
+ */
392
+ static register(component: CustomElementConstructor | typeof Component, tagName?: string): void;
393
+ /**
394
+ * The HTML tag name to use for this Component
395
+ */
396
+ static tagName: string;
397
+ /**
398
+ * An HTML Template element for this element to use.
399
+ */
400
+ static template: HTMLTemplateElement | Template;
401
+ /**
402
+ * A {@link CSSStyleSheet} array to adopt to the element's shadow DOM
403
+ */
404
+ static styles: ComponentStyles;
405
+ /**
406
+ * An array of html attribute names to observe to trigger updates.
407
+ *
408
+ * @remarks
409
+ * If you use the {@link define} factory helper, this value will be
410
+ * automatically merged with a list of any defined {@link liveAttributes}.
411
+ */
412
+ static observedAttributes: string[];
413
+ /**
414
+ * The mode for this Component's ShadowRoot.
415
+ *
416
+ * - `"open"` allows JS access to the children of this component
417
+ * - `"closed"` (default) disallows internal JS access
418
+ */
419
+ static shadowRootMode: "closed" | "open";
420
+ /**
421
+ * Called immediately before each template update
422
+ */
423
+ protected beforeUpdate?(): void;
424
+ /**
425
+ * Called immediately after each template update
426
+ */
427
+ protected afterUpdate?(previousAttributes: Map<string, string | null>): void;
428
+ /**
429
+ * Called as the final lifecycle method at the end of the unmounting process.
430
+ *
431
+ * Content has been removed from the DOM and the component is no longer
432
+ * considered mounted when this function runs.
433
+ *
434
+ * Use this for final cleanup tasks and freeing resources.
435
+ */
436
+ protected finalize?(): void;
437
+ /**
438
+ * If defined, receives errors caught during the lifecycle methods of this
439
+ * component and it's children. If not defined, this component will instead
440
+ * throw errors as they are found.
441
+ *
442
+ * If the error cannot be handled, `onError()` should re-throw it for a higher
443
+ * up component to evaluate.
444
+ *
445
+ * To display an error message while removing an erroring component from the
446
+ * DOM, use `this.replaceWith()` and a newly constructed placeholder element.
447
+ *
448
+ * @example
449
+ *
450
+ * Recovering from errors or displaying a fallback
451
+ *
452
+ * ```typescript
453
+ * onError(error) {
454
+ * // Handle known errors
455
+ * if (error.message = "Invalid Input") {
456
+ * this.state.input = "";
457
+ * return;
458
+ * }
459
+ *
460
+ * // Display a fallback banner
461
+ * const banner = document.createElement("div");
462
+ * banner.textContent = "An unexpected error done did";
463
+ * this.replaceWith(banner);
464
+ * }
465
+ * ```
466
+ */
467
+ protected onError?(error: unknown): void;
468
+ /**
469
+ * The initial value for this Component's reactive internal state, if any.
470
+ *
471
+ * If `initialState` is defined as a function, the function is evaluated at
472
+ * mounting time and the return value is used as the initial state.
473
+ */
474
+ protected initialState?: StateInitializer<StateShape>;
475
+ /**
476
+ * An object or function returning an object which populates the `data` values
477
+ * in the templating engine. Such values are accessed using the `*` notation.
478
+ *
479
+ * When a hosted value is accessed, it's value is coerced based on the way it
480
+ * is being used. For attributes, values are serialized to a string or null,
481
+ * which will set the attribute (string) or remove it (null).
482
+ *
483
+ * For content swaps, strings, numbers and booleans are rendered as strings
484
+ * and set as textContent. null and undefined values render nothing (with a
485
+ * comment placeholder), an HTMLElement will be swapped in as a cloned node.
486
+ *
487
+ * Functions are evaluated at render/update time, and their return value is
488
+ * used instead. Functions are passed the current target node accessing the
489
+ * property as its first and only argument.
490
+ *
491
+ * Other types are unsupported.
492
+ *
493
+ * @example
494
+ *
495
+ * ```typescript
496
+ * host = {
497
+ * avatarUrl: "http://...",
498
+ * renderTime: () => new Date().toISOString(),
499
+ * }
500
+ * ```
501
+ *
502
+ * ```html
503
+ * <img :src="*avatarUrl" />
504
+ * <span>Rendered at ${"*renderTime"}</span>
505
+ * ```
506
+ */
507
+ protected computedProperties?: ComputedProperties<StateShape>;
508
+ /**
509
+ * Declaration of attribute behaviors during updates.
510
+ *
511
+ * Each key is the name of an attribute. Values are an object with two
512
+ * optional function definitions:
513
+ *
514
+ * `onChange(newValue, oldValue): void`, a handler function for when the value
515
+ * of this attribute has changed. Runs once per update cycle, *before* the
516
+ * update occurs.
517
+ *
518
+ * `reflect(): unknown`, a function which returns a value to serialize and set
519
+ * as this attribute *after* an update completes.
520
+ *
521
+ * @example
522
+ *
523
+ * ```typescript
524
+ * liveAttributes = {
525
+ * done: {
526
+ * onChange(newValue) {
527
+ * this.state.set("done", !!newValue);
528
+ * },
529
+ * reflect() { return this.state.current.done }
530
+ * }
531
+ * };
532
+ * ```
533
+ *
534
+ * @remarks
535
+ *
536
+ * If using the {@link define} helper, the keys of this property are
537
+ * automatically merged with any defined {@link observedAttributes}.
538
+ *
539
+ * If you are directly extending the class, `observedAttributes` must be
540
+ * explicitly defined with any attributes that should be monitored, regardless
541
+ * of if they're defined here.
542
+ */
543
+ protected liveAttributes?: LiveAttributes<StateShape>;
544
+ private _isComponentMounted;
545
+ private _template;
546
+ private _root;
547
+ private _state?;
548
+ private _delegator?;
549
+ private _ownListeners;
550
+ private _liveAttributeConfigs;
551
+ private _nextListenerAutoId;
552
+ private _cleanupFn?;
553
+ private _renderInternals;
554
+ constructor();
555
+ /** Produce the data object to pass to the template's render function */
556
+ private _getRenderContext;
557
+ private _safeGetState;
558
+ private _reportError;
559
+ private _executeAttributeChangeHandlers;
560
+ private _reflectLiveAttributes;
561
+ /** The actual update behavior */
562
+ private _performUpdate;
563
+ /** Safely request for an update to run on the next frame */
564
+ private _scheduleUpdate;
565
+ private _adoptState;
566
+ /**
567
+ * @deprecated Use {@link script} instead
568
+ */
569
+ protected connectedCallback(): void;
570
+ /**
571
+ * @deprecated use {@link finalize}
572
+ */
573
+ protected disconnectedCallback(): void;
574
+ /**
575
+ * @deprecated Use {@link liveAttributes} instead
576
+ */
577
+ protected attributeChangedCallback(name: string, _: string | null, newValue: string | null): void;
578
+ /**
579
+ * The ShadowRoot node of this element
580
+ */
581
+ get root(): ShadowRoot;
582
+ /**
583
+ * Directly access and manipulate this Component's reactive state with deep
584
+ * reactivity enabled.
585
+ *
586
+ * @example
587
+ *
588
+ * ```typescript
589
+ * initialState = { values: { count: 1, time: 0 } };
590
+ *
591
+ * increment() {
592
+ * this.state.values.count = 2;
593
+ * }
594
+ * ```
595
+ *
596
+ * @remarks
597
+ * This is a shorthand getter for `this.getState().live`
598
+ */
599
+ get state(): StateShape;
600
+ /**
601
+ * Replace the current state with a new value or adopt a whole different State
602
+ * instance
603
+ *
604
+ * @example
605
+ *
606
+ * State replacement
607
+ *
608
+ * ```typescript
609
+ * // Always triggers a render
610
+ * this.state = { some: "newState" }
611
+ *
612
+ * // Adopt a new state instance altogether
613
+ * const otherState = new State({some: "newState"});
614
+ * this.state = otherState;
615
+ *
616
+ * // Causes a render
617
+ * otherState.set("some", "value");
618
+ * ```
619
+ */
620
+ set state(newState: StateShape | State<StateShape>);
621
+ /**
622
+ * Access the full {@link State} instance for this Component.
623
+ *
624
+ * Using this method on a component which is not using reactive state
625
+ * will result in an error being thrown.
626
+ *
627
+ * @example
628
+ *
629
+ * Retrieve stateful value
630
+ *
631
+ * ```typescript
632
+ * class Example extends Component {
633
+ * initialState = { count: 1 };
634
+ *
635
+ * script() {
636
+ * const state = this.getState();
637
+ * console.log(`The count is ${state.get("count")}`);
638
+ * }
639
+ *
640
+ * }
641
+ * ```
642
+ *
643
+ * @example
644
+ *
645
+ * Set a stateful value
646
+ *
647
+ * ```typescript
648
+ * class Example extends Component {
649
+ * initialState = { count: 1 };
650
+ *
651
+ * increment() {
652
+ * const state = this.getState();
653
+ * const current = state.get("count");
654
+ * state.set("count", current + 1);
655
+ * }
656
+ * }
657
+ * ```
658
+ */
659
+ getState(): State<StateShape>;
660
+ /**
661
+ * Manually schedule a render to occur
662
+ *
663
+ * @remarks
664
+ * Calling {@link requestRender} multiple times in the same event loop won't
665
+ * schedule multiple renders. Renders are scheduled to occur on the next
666
+ * animation frame.
667
+ */
668
+ requestRender(callback?: VoidFunction): void;
669
+ /**
670
+ * Create a managed event listener on this Component with an optional query
671
+ * filter string to specify which elements to listen to events from.
672
+ *
673
+ * Event handlers set up with `listen()` are automatically cleaned up when
674
+ * the component is unmounted. Event listeners are executed with this instance
675
+ * as the `this` binding.
676
+ *
677
+ * Handlers are delegated to a single listener per event on the root of the
678
+ * Component, which is the closed ShadowRoot by default.
679
+ *
680
+ * @example
681
+ *
682
+ * Set up an event listener for a click event from a button with ID "submit"
683
+ *
684
+ * ```typescript
685
+ * this.listen("#submit", "click", this.handleClick);
686
+ * ```
687
+ *
688
+ * @example
689
+ *
690
+ * Set up an event listener on the host element itself (`this`).
691
+ *
692
+ * ```typescript
693
+ * // Use ":host" or ":HOST" as the query selector to targe the host element
694
+ * this.listen(":host", "animationend", this.handler);
695
+ * ```
696
+ */
697
+ listen<E extends EventName>(targetDescriptor: string | typeof Component<any> | HTMLElement, eventName: E, eventHandler: EventHandler<E>): void;
698
+ dispatchEvent(event: Event): boolean;
699
+ /**
700
+ * Dispatch a {@link CustomEvent} with the specified name and detail
701
+ *
702
+ * @example Defining custom events
703
+ *
704
+ * ```typescript
705
+ * // Define types. This can happen in the same file or elsewhere for common
706
+ * // and shared events.
707
+ * type MyEvent = CustomEvent<T> // Set `T` to the event detail type
708
+ *
709
+ * declare global {
710
+ * interface GlobalEventHandlersEventMap {
711
+ * "my-event-name": MyEvent
712
+ * }
713
+ * }
714
+ *
715
+ * // Dispatch a custom event
716
+ * this.dispatchEvent("my-event-name", T);
717
+ *
718
+ * // Listen to a custom event
719
+ * $el.addEventListener("my-event-name", ...);
720
+ * ```
721
+ */
722
+ dispatchEvent<T>(event: string, detail?: T, options?: {
723
+ bubbles: boolean;
724
+ cancelable: boolean;
725
+ composed: boolean;
726
+ }): boolean;
727
+ querySelector<E extends HTMLElement>(query: string): E | null;
728
+ querySelectorAll<E extends HTMLElement>(query: string): NodeListOf<E>;
729
+ getElementById<E extends HTMLElement>(id: string): E | null;
730
+ requireElementById<E extends HTMLElement>(id: string): E;
731
+ setAttribute(name: string, value: string): void;
732
+ /**
733
+ * Set a value as an attribute, serializing to a string or `null`.
734
+ *
735
+ * null values cause the attribute to be removed from this element
736
+ */
737
+ setAttribute(name: string, value: unknown): void;
738
+ getAttribute(name: string): string | null;
739
+ /**
740
+ * Get an attribute as a number, falling back to a specified default.
741
+ *
742
+ *
743
+ * `null` attributes are returned as `null`, while string attributes are
744
+ * parsed using the `Number()` constructor.
745
+ *
746
+ * Values which evaluate to NaN are returned as `null`.
747
+ */
748
+ getAttribute(name: string, defaultValue: number): number;
749
+ /**
750
+ * Get an attribute as a string, falling back to a specified default
751
+ */
752
+ getAttribute(name: string, defaultValue: string): string;
753
+ /**
754
+ * Set the value of an attribute on this element if the provided value
755
+ * differs from the attribute when serialized
756
+ */
757
+ reflectAttribute(name: string, value: unknown): void;
758
+ /**
759
+ * Serialize this element to a string
760
+ */
761
+ toString(full?: boolean): string;
762
+ }
763
+ interface ComponentShorthand<StateShape extends object = {}> {
764
+ /**
765
+ * An HTML Template element for this element to use.
766
+ */
767
+ template?: HTMLTemplateElement;
768
+ /**
769
+ * A {@link CSSStyleSheet} array to adopt to the element's shadow DOM
770
+ */
771
+ styles?: ComponentStyles;
772
+ /**
773
+ * The mode for this Component's ShadowRoot.
774
+ *
775
+ * - `"open"` allows JS access to the children of this component
776
+ * - `"closed"` (default) disallows internal JS access
777
+ */
778
+ shadowRootMode?: "closed" | "open";
779
+ /**
780
+ * The initial state for this Component's reactive internal state, if any.
781
+ */
782
+ initialState?: StateInitializer<StateShape>;
783
+ /**
784
+ * An object or function returning an object which populates the `data` values
785
+ * in the templating engine. Such values are accessed using the `*` notation.
786
+ */
787
+ computedProperties?: ComputedProperties<StateShape>;
788
+ /**
789
+ * Declaration of attribute behaviors during updates.
790
+ */
791
+ liveAttributes?: LiveAttributes<StateShape>;
792
+ /**
793
+ * Initialization scripting for this Component
794
+ */
795
+ script?: (this: Component<StateShape>) => VoidFunction | void;
796
+ /**
797
+ * Called immediately before each template update
798
+ */
799
+ beforeUpdate?: (this: Component<StateShape>) => void;
800
+ /**
801
+ * Called immediately after each template update
802
+ */
803
+ afterUpdate?: (this: Component<StateShape>, previousAttributes: AttributeMap) => void;
804
+ /**
805
+ * Called as the final lifecycle method at the end of the unmounting process.
806
+ *
807
+ * Content has been removed from the DOM and the component is no longer
808
+ * considered mounted when this function runs.
809
+ *
810
+ * Use this for final cleanup tasks and freeing resources.
811
+ */
812
+ finalize?: (this: Component<StateShape>) => void;
813
+ /**
814
+ * If defined, receives errors caught during the lifecycle methods of this
815
+ * component and it's children. If not defined, this component will instead
816
+ * throw errors as they are found.
817
+ *
818
+ * If the error cannot be handled, `onError()` should re-throw it for a higher
819
+ * up component to evaluate.
820
+ *
821
+ * To display an error message while removing an erroring component from the
822
+ * DOM, use `this.replaceWith()` and a newly constructed placeholder element.
823
+ *
824
+ * @example
825
+ *
826
+ * Recovering from errors or displaying a fallback
827
+ *
828
+ * ```typescript
829
+ * onError(error) {
830
+ * // Handle known errors
831
+ * if (error.message = "Invalid Input") {
832
+ * this.state.input = "";
833
+ * return;
834
+ * }
835
+ *
836
+ * // Display a fallback banner
837
+ * const banner = document.createElement("div");
838
+ * banner.textContent = "An unexpected error done did";
839
+ * this.replaceWith(banner);
840
+ * }
841
+ * ```
842
+ */
843
+ onError?: (this: Component<StateShape>, error: unknown) => void;
844
+ }
845
+ declare function define<StateShape extends object = {}>(tagname: string, definition: ComponentShorthand<StateShape>): typeof Component<StateShape>;
846
+ /**
847
+ * An error originating from within a Palette subsystem.
848
+ *
849
+ * In the `development` environment, the error will surface with extended info
850
+ * about the error and any details which may be relevant to help with debugging.
851
+ *
852
+ * In the `production` environment, a minimal error only surfacing the numeric
853
+ * error code is thrown instead.
854
+ *
855
+ * Codes are categorized into groups by the 100's:
856
+ *
857
+ * - 0 - 99: Invariants
858
+ * - 100 - 199: Custom Elements / Environment Errors
859
+ * - 200 - 299: Templating Errors
860
+ * - 300 - 399: Runtime Errors
861
+ */
862
+ declare class PaletteError extends Error {
863
+ name: string;
864
+ code: number;
865
+ constructor(code: number, ...values: string[]);
866
+ }
867
+ /**
868
+ * @returns An array of {@link CSSStyleSheet}s containing the provided CSS
869
+ */
870
+ declare function css(strings: TemplateStringsArray, ...values: unknown[]): CSSStyleSheet;
871
+ type ClassValue = string | number | boolean | undefined | null | ClassArray | ClassObject;
872
+ type ClassArray = ClassValue[];
873
+ type ClassObject = Record<string, any>;
874
+ /**
875
+ * Given flexible input, generate a string suitable for setting as an html class
876
+ *
877
+ * @example
878
+ *
879
+ * ```typescript
880
+ * classify("my-class", "another-class") // "my-class another-class"
881
+ * classify(["my-class", "another-class"]) // "my-class another-class"
882
+ * classify({ enabled: true, disabled: false }) // "enabled"
883
+ * ```
884
+ */
885
+ declare function classify(...args: ClassValue[]): string;
886
+ /**
887
+ * Create an {@link HTMLTemplateElement} from the provided HTML string.
888
+ *
889
+ * These HTML Templates can be used as standard HTML Templates, or as the
890
+ * foundation for a {@link Component} or standalone {@link Template}
891
+ *
892
+ * Interpolates values in the template string to provide helpers for composing
893
+ * templates:
894
+ *
895
+ * - HTMLTemplateElement references are serialized to HTML and inlined
896
+ * - Strings are modified to become <span> tags with the ::swap directive set
897
+ * to the string value. This is helpful shorthand for content placeholders.
898
+ *
899
+ * @example
900
+ *
901
+ * This template string
902
+ *
903
+ * ```typescript
904
+ * const $template = html`
905
+ * <div :class="*classnames">
906
+ * ${"@content"}
907
+ * </div>
908
+ * `
909
+ * ```
910
+ *
911
+ * Produces this template element (portrayed as HTML)
912
+ *
913
+ * ```html
914
+ * <template>
915
+ * <div :class="*classnames">
916
+ * <span ::swap="@content"></span>
917
+ * </div>
918
+ * </template>
919
+ * ```
920
+ */
921
+ declare function html(strings: TemplateStringsArray, ...values: (`@${string}` | `$${string}` | `#${string}` | `*${string}` | HTMLTemplateElement | typeof Component<any>)[]): HTMLTemplateElement;
922
+ export { html, define, css, classify, TemplateRoot, TemplateContext, Template, StateListener, StateInitializer, State, PaletteError, LiveAttributes, EventName, EventHandler, ComputedProperties, ComponentStyles, ComponentShorthand, Component, AttributeMap };