@rusticarcade/palette 0.2.0 → 0.3.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.
- package/README.md +73 -1
- package/dist/dev/index.js +1 -1
- package/dist/prod/index.js +2 -2
- package/dist/test/index.d.ts +803 -0
- package/dist/test/index.js +347 -0
- package/package.json +37 -10
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize the global test DOM environment (using HappyDOM)
|
|
3
|
+
*/
|
|
4
|
+
declare function prepareGlobalTestDOM(): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Cleanup the global test DOM environment (using HappyDOM)
|
|
7
|
+
*/
|
|
8
|
+
declare function cleanupGlobalTestDOM(): Promise<void>;
|
|
9
|
+
type StateListener<Shape> = (state: Shape) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Powerful and flexible state management with deep reactivity, transaction, and
|
|
12
|
+
* locking support.
|
|
13
|
+
*
|
|
14
|
+
* The State class wraps stateful data and provides an API for mutating the data
|
|
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
|
+
*/
|
|
31
|
+
declare class State<Shape extends object> {
|
|
32
|
+
private _data;
|
|
33
|
+
private _listeners;
|
|
34
|
+
private _proxy?;
|
|
35
|
+
private _proxyCache;
|
|
36
|
+
private _reverseProxyCache;
|
|
37
|
+
private _isLocked;
|
|
38
|
+
private _hasWarned;
|
|
39
|
+
constructor(initialData: Shape, onChange?: StateListener<Shape>);
|
|
40
|
+
/**
|
|
41
|
+
* Lazily create and cache proxies into the state for reactive updates on
|
|
42
|
+
* nested values.
|
|
43
|
+
*/
|
|
44
|
+
private _createProxy;
|
|
45
|
+
private _unwrapProxy;
|
|
46
|
+
/**
|
|
47
|
+
* Handle setting nested values and emitting updated data if the value changed
|
|
48
|
+
*/
|
|
49
|
+
private _setNested;
|
|
50
|
+
/**
|
|
51
|
+
* Process an incoming partial state and emit updates to listeners if there
|
|
52
|
+
* are any changes detected.
|
|
53
|
+
*
|
|
54
|
+
* @remarks
|
|
55
|
+
* Object.is() to check for differences. Does not attempt deep diffing.
|
|
56
|
+
*/
|
|
57
|
+
private _processIncomingState;
|
|
58
|
+
/**
|
|
59
|
+
* Emit the current state to all listeners
|
|
60
|
+
*/
|
|
61
|
+
private _emit;
|
|
62
|
+
/**
|
|
63
|
+
* The current state
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* This is a direct reference to the internal state. It is marked as Readonly
|
|
67
|
+
* to help prevent accidental changes. Never edit this value directly.
|
|
68
|
+
*/
|
|
69
|
+
get current(): Readonly<Shape>;
|
|
70
|
+
/**
|
|
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;
|
|
88
|
+
*
|
|
89
|
+
* // Array mutators are automatically reactive as well
|
|
90
|
+
* state.live.nested.values.push(4);
|
|
91
|
+
* state.live.nested.values.reverse();
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
get live(): Shape;
|
|
95
|
+
/**
|
|
96
|
+
* Indicates if this state is currently locked (true) or not (false)
|
|
97
|
+
*/
|
|
98
|
+
get isLocked(): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Add a handler function for when this state changes.
|
|
101
|
+
*
|
|
102
|
+
* Listeners are invoked in the order they are registered and are passed a
|
|
103
|
+
* reference to the internally managed state object as a readonly object.
|
|
104
|
+
*
|
|
105
|
+
* **Do not modify state values directly**. Instead, use {@link set} or
|
|
106
|
+
* {@link patch} to make immutable updates.
|
|
107
|
+
*/
|
|
108
|
+
addListener: (listener: StateListener<Shape>) => void;
|
|
109
|
+
/**
|
|
110
|
+
* Remove a previously registered state handler
|
|
111
|
+
*/
|
|
112
|
+
removeListener: (listener: StateListener<Shape>) => void;
|
|
113
|
+
/**
|
|
114
|
+
* Get a single value from the state object
|
|
115
|
+
*
|
|
116
|
+
* The value is returned as Readonly to prevent accidental state mutations.
|
|
117
|
+
* 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
|
+
*/
|
|
127
|
+
get: <K extends keyof Shape>(key: K) => Readonly<Shape[K]>;
|
|
128
|
+
/**
|
|
129
|
+
* Returns a deep clone of the current state data using `structuredClone()` to
|
|
130
|
+
* make the copy.
|
|
131
|
+
*
|
|
132
|
+
* The object returned from this function can be edited without modifying the
|
|
133
|
+
* actual internal state.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
*
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const snap = state.snapshot();
|
|
139
|
+
* snap.count += 1;
|
|
140
|
+
* state.patch(snap);
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
snapshot: () => Shape;
|
|
144
|
+
/**
|
|
145
|
+
* Set a single stateful property while leaving other properties unchanged.
|
|
146
|
+
*
|
|
147
|
+
* Triggers an update to all listeners if the value is different from before
|
|
148
|
+
* when compared using shallow equality.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
*
|
|
152
|
+
* ```typescript
|
|
153
|
+
* const state = new State({ count: 1, color: "red" });
|
|
154
|
+
* state.set("count", 2); // State is now { count: 2, color: "red" }
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
set: <K extends keyof Shape>(key: K, value: Shape[K]) => void;
|
|
158
|
+
/**
|
|
159
|
+
* Set multiple stateful properties at once, leaving omitted properties
|
|
160
|
+
* 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
|
+
*/
|
|
180
|
+
patch: (patch: Partial<Shape>) => State<Shape>;
|
|
181
|
+
/**
|
|
182
|
+
* Fully replace the current state data and force listeners to receive the
|
|
183
|
+
* updated data immediately.
|
|
184
|
+
*/
|
|
185
|
+
replace: (state: Shape) => State<Shape>;
|
|
186
|
+
/**
|
|
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
|
+
* Apply complex updates to the state using a mutator function.
|
|
196
|
+
*
|
|
197
|
+
* The mutator function takes one parameter which is a structuredClone copy of
|
|
198
|
+
* the current state object. Whatever is returned by the mutator is then
|
|
199
|
+
* patched in to the state.
|
|
200
|
+
*/
|
|
201
|
+
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>;
|
|
283
|
+
}
|
|
284
|
+
type TemplateRoot = HTMLElement | ShadowRoot;
|
|
285
|
+
type TemplateContext = {
|
|
286
|
+
attr?: Record<string, string | null>;
|
|
287
|
+
state?: Record<string, unknown>;
|
|
288
|
+
data?: Record<string, unknown>;
|
|
289
|
+
item?: Record<string, unknown>;
|
|
290
|
+
index?: number;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* A renderable template from an HTMLTemplateElement
|
|
294
|
+
*
|
|
295
|
+
* Leverages a simple syntax to provide accessors to template data from one of
|
|
296
|
+
* four categories, based on use case:
|
|
297
|
+
*
|
|
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
|
+
* ```
|
|
304
|
+
*
|
|
305
|
+
* Bind attributes to a value using the `:attribute` syntax:
|
|
306
|
+
*
|
|
307
|
+
* ```html
|
|
308
|
+
* <div :id="$id" :class="@classname"></div>
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
declare class Template {
|
|
312
|
+
/**
|
|
313
|
+
* Properties related to the global Template build cache.
|
|
314
|
+
*
|
|
315
|
+
* This is not something typically needed for general app development, but
|
|
316
|
+
* allows for advanced configuration to tune the caching system if need be.
|
|
317
|
+
*
|
|
318
|
+
* Cache sizes default to 500 HTML Template Fragments and compiled Palette
|
|
319
|
+
* templates (includes nested templates like lists) to cover most application
|
|
320
|
+
* needs without using much memory.
|
|
321
|
+
*/
|
|
322
|
+
static cache: {
|
|
323
|
+
/**
|
|
324
|
+
* Wipe all cached templates and HTML fragments
|
|
325
|
+
*/
|
|
326
|
+
clear: () => void;
|
|
327
|
+
/**
|
|
328
|
+
* the default cache capacity of 500 items per cache
|
|
329
|
+
*
|
|
330
|
+
* General caching guidance:
|
|
331
|
+
* - 95% of the time, 500 works fine
|
|
332
|
+
* - For very large applications, up to 1000 is reasonable
|
|
333
|
+
* - For smaller apps, dropping down to 100 - 250 may save memory
|
|
334
|
+
*
|
|
335
|
+
* Ultimately the impact will be minimal unless your app has very specific
|
|
336
|
+
* rendering needs.
|
|
337
|
+
*/
|
|
338
|
+
setCapacity: (maxSize: number) => void;
|
|
339
|
+
};
|
|
340
|
+
private _compiled;
|
|
341
|
+
/**
|
|
342
|
+
* The original {@link HTMLTemplateElement} used to create this Template.
|
|
343
|
+
*
|
|
344
|
+
* @remarks
|
|
345
|
+
* Make sure to never operate directly on this element. Always clone.
|
|
346
|
+
*/
|
|
347
|
+
private _templateElement?;
|
|
348
|
+
/** The current known root element that this Template is rendered into */
|
|
349
|
+
private _mountedRoot?;
|
|
350
|
+
/** The most recent set value for each notation that has rendered */
|
|
351
|
+
private _latestRenderedValues;
|
|
352
|
+
/** The active HTMLElement which the template is updating on renders */
|
|
353
|
+
private _fragment;
|
|
354
|
+
/** Value Notations -> Set<Render Plans> */
|
|
355
|
+
private _plansByNotation;
|
|
356
|
+
/** Value Notations -> Accessor functions */
|
|
357
|
+
private _notationAccessors;
|
|
358
|
+
constructor(template: HTMLTemplateElement);
|
|
359
|
+
/**
|
|
360
|
+
* Create a full copy of this template for use in rendering to another root
|
|
361
|
+
*/
|
|
362
|
+
clone: () => Template;
|
|
363
|
+
/**
|
|
364
|
+
* @returns An {@link HTMLTemplateElement} representing this template
|
|
365
|
+
*/
|
|
366
|
+
element: () => HTMLTemplateElement;
|
|
367
|
+
private _collectUpdatedValues;
|
|
368
|
+
private _update;
|
|
369
|
+
/**
|
|
370
|
+
* Render this template into a target host element.
|
|
371
|
+
*/
|
|
372
|
+
render: (root: TemplateRoot, context: TemplateContext) => void;
|
|
373
|
+
}
|
|
374
|
+
type EventName = keyof GlobalEventHandlersEventMap;
|
|
375
|
+
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
|
+
};
|
|
381
|
+
}
|
|
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
|
+
/**
|
|
387
|
+
* The **Component** class extends the base HTMLElement class to provide an
|
|
388
|
+
* ergonomic way to design and develop Web Components with reactive state,
|
|
389
|
+
* managed attributes, and dynamic templating.
|
|
390
|
+
*/
|
|
391
|
+
declare abstract class Component<StateShape extends object = {}> extends HTMLElement {
|
|
392
|
+
/**
|
|
393
|
+
* Register a Component with the browser. Optionally provide an overriding
|
|
394
|
+
* tag name.
|
|
395
|
+
*/
|
|
396
|
+
static register(component: CustomElementConstructor | typeof Component, tagName?: string): void;
|
|
397
|
+
/**
|
|
398
|
+
* The HTML tag name to use for this Component
|
|
399
|
+
*/
|
|
400
|
+
static tagName: string;
|
|
401
|
+
/**
|
|
402
|
+
* An HTML Template element for this element to use.
|
|
403
|
+
*/
|
|
404
|
+
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
|
+
*/
|
|
416
|
+
static observedAttributes: string[];
|
|
417
|
+
/**
|
|
418
|
+
* The mode for this Component's ShadowRoot.
|
|
419
|
+
*
|
|
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
|
|
426
|
+
*/
|
|
427
|
+
protected beforeUpdate?(): void;
|
|
428
|
+
/**
|
|
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.
|
|
439
|
+
*/
|
|
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>;
|
|
479
|
+
/**
|
|
480
|
+
* An object or function returning an object which populates the `data` values
|
|
481
|
+
* 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
|
+
*/
|
|
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;
|
|
557
|
+
constructor();
|
|
558
|
+
/** Produce the data object to pass to the template's render function */
|
|
559
|
+
private _getRenderContext;
|
|
560
|
+
private _escalateError;
|
|
561
|
+
private _reportError;
|
|
562
|
+
private _executeAttributeChangeHandlers;
|
|
563
|
+
private _reflectLiveAttributes;
|
|
564
|
+
/** The actual update behavior */
|
|
565
|
+
private _performUpdate;
|
|
566
|
+
/** Safely request for an update to run on the next frame */
|
|
567
|
+
private _scheduleUpdate;
|
|
568
|
+
private _adoptState;
|
|
569
|
+
/**
|
|
570
|
+
* @deprecated Use {@link script} instead
|
|
571
|
+
*/
|
|
572
|
+
protected connectedCallback(): void;
|
|
573
|
+
/**
|
|
574
|
+
* @deprecated use {@link finalize}
|
|
575
|
+
*/
|
|
576
|
+
protected disconnectedCallback(): void;
|
|
577
|
+
/**
|
|
578
|
+
* @deprecated Use {@link liveAttributes} instead
|
|
579
|
+
*/
|
|
580
|
+
protected attributeChangedCallback(name: string, _: string | null, newValue: string | null): void;
|
|
581
|
+
/**
|
|
582
|
+
* The ShadowRoot node of this element
|
|
583
|
+
*/
|
|
584
|
+
get root(): ShadowRoot;
|
|
585
|
+
/**
|
|
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 } };
|
|
593
|
+
*
|
|
594
|
+
* increment() {
|
|
595
|
+
* this.state.values.count = 2;
|
|
596
|
+
* }
|
|
597
|
+
* ```
|
|
598
|
+
*
|
|
599
|
+
* @remarks
|
|
600
|
+
* This is a shorthand getter for `this.getState().live`
|
|
601
|
+
*/
|
|
602
|
+
get state(): StateShape;
|
|
603
|
+
/**
|
|
604
|
+
* Replace the current state with a new value or adopt a whole different State
|
|
605
|
+
* 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
|
+
*/
|
|
623
|
+
set state(newState: StateShape | State<StateShape>);
|
|
624
|
+
/**
|
|
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
|
|
665
|
+
*
|
|
666
|
+
* @remarks
|
|
667
|
+
* Calling {@link requestRender} multiple times in the same event loop won't
|
|
668
|
+
* schedule multiple renders. Renders are scheduled to occur on the next
|
|
669
|
+
* animation frame.
|
|
670
|
+
*/
|
|
671
|
+
requestRender(callback?: VoidFunction): void;
|
|
672
|
+
/**
|
|
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.
|
|
675
|
+
*
|
|
676
|
+
* Event handlers set up with `listen()` are automatically cleaned up when
|
|
677
|
+
* the component is unmounted.
|
|
678
|
+
*
|
|
679
|
+
* Handlers are delegated to a single listener per event on the root of the
|
|
680
|
+
* Component, which is the closed ShadowRoot by default.
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
*
|
|
684
|
+
* Set up an event listener for a click event from a button with ID "submit"
|
|
685
|
+
*
|
|
686
|
+
* ```typescript
|
|
687
|
+
* this.listen("#submit", "click", this.handleClick);
|
|
688
|
+
* ```
|
|
689
|
+
*
|
|
690
|
+
* @example
|
|
691
|
+
*
|
|
692
|
+
* Set up an event listener on the host element itself (`this`).
|
|
693
|
+
*
|
|
694
|
+
* ```typescript
|
|
695
|
+
* // Use ":host" or ":HOST" as the query selector to targe the host element
|
|
696
|
+
* this.listen(":host", "animationend", this.handler);
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
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;
|
|
702
|
+
/**
|
|
703
|
+
* Dispatch a {@link CustomEvent} with the specified name and detail
|
|
704
|
+
*
|
|
705
|
+
* @example Defining custom events
|
|
706
|
+
*
|
|
707
|
+
* ```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
|
+
* }
|
|
716
|
+
* }
|
|
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
|
+
* ```
|
|
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
|
+
*
|
|
738
|
+
* null values cause the attribute to be removed from this element
|
|
739
|
+
*/
|
|
740
|
+
setAttribute(name: string, value: unknown): void;
|
|
741
|
+
getAttribute(name: string): string | null;
|
|
742
|
+
/**
|
|
743
|
+
* Get an attribute as a number, falling back to a specified default.
|
|
744
|
+
*
|
|
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
|
|
759
|
+
*/
|
|
760
|
+
reflectAttribute(name: string, value: unknown): void;
|
|
761
|
+
/**
|
|
762
|
+
* Serialize this element to a string
|
|
763
|
+
*/
|
|
764
|
+
toString(full?: boolean): string;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Render a Palette Component class as a test element
|
|
768
|
+
*
|
|
769
|
+
* If the class is not yet registered, it is auto-registered before creation.
|
|
770
|
+
*
|
|
771
|
+
* @example
|
|
772
|
+
*
|
|
773
|
+
* ```typescript
|
|
774
|
+
* test("component does something", async () => {
|
|
775
|
+
* let somethingMock = mock();
|
|
776
|
+
*
|
|
777
|
+
* class MyTestComponent extends Component {
|
|
778
|
+
* script() {
|
|
779
|
+
* somethingMock();
|
|
780
|
+
* }
|
|
781
|
+
* }
|
|
782
|
+
*
|
|
783
|
+
* await renderTestComponent(MyTestComponent);
|
|
784
|
+
* expect(somethingMock).toHaveBeenCalled();
|
|
785
|
+
* });
|
|
786
|
+
* ```
|
|
787
|
+
*
|
|
788
|
+
* @param component The component class to register and create
|
|
789
|
+
* @param attributes A record of attributes to apply
|
|
790
|
+
* @returns A reference to the rendered Component
|
|
791
|
+
*/
|
|
792
|
+
declare function renderTestComponent<E extends typeof Component<any>>(component: E, attributes?: Record<string, unknown>): Promise<InstanceType<E>>;
|
|
793
|
+
/**
|
|
794
|
+
* Force a render on the target element
|
|
795
|
+
*
|
|
796
|
+
* Returns a promise which resolves when the render has completed
|
|
797
|
+
*/
|
|
798
|
+
declare function rerenderTestComponent(element: Component): Promise<void>;
|
|
799
|
+
/**
|
|
800
|
+
* Returns a random tag name for use in a test element
|
|
801
|
+
*/
|
|
802
|
+
declare const randomTagName: () => string;
|
|
803
|
+
export { rerenderTestComponent, renderTestComponent, randomTagName, prepareGlobalTestDOM, cleanupGlobalTestDOM };
|