@rusticarcade/palette 0.3.1 → 0.4.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.
@@ -27,7 +27,6 @@ declare class State<Shape extends object> {
27
27
  private _proxyCache;
28
28
  private _reverseProxyCache;
29
29
  private _isLocked;
30
- private _hasWarned;
31
30
  constructor(initialData: Shape, onChange?: StateListener<Shape>);
32
31
  /**
33
32
  * Lazily create and cache proxies into the state for reactive updates on
@@ -60,28 +59,12 @@ declare class State<Shape extends object> {
60
59
  */
61
60
  get current(): Readonly<Shape>;
62
61
  /**
63
- * Proxied access to state properties with automatic reconciliation.
62
+ * Live reactive accessor for state data. Deeply nested changes trigger
63
+ * automatic updates, including array, Map, and Set mutations.
64
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
- * ```
65
+ * @remarks
66
+ * For deeply nested values, the `.live` accessor may add performance overhead
67
+ * compared to directly accessing the value via `.current`
85
68
  */
86
69
  get live(): Shape;
87
70
  /**
@@ -273,6 +256,72 @@ declare class State<Shape extends object> {
273
256
  */
274
257
  transactionAsync: (fn: (state: State<Shape>) => Promise<void>) => Promise<boolean>;
275
258
  }
259
+ type ParsedNotation = {
260
+ /** The raw string representation of the parsed notation */
261
+ base: string;
262
+ /** An array of property names forming a path to the notation value */
263
+ path: string[];
264
+ modifiers?: {
265
+ not?: boolean;
266
+ };
267
+ };
268
+ type NotationAccessor = (source: unknown) => unknown;
269
+ declare const enum Directive {
270
+ Each = "::each",
271
+ Key = "::key",
272
+ Tag = "::tag",
273
+ Swap = "::swap",
274
+ If = "::if",
275
+ ElseIf = "::else-if",
276
+ Else = "::else"
277
+ }
278
+ type ConditionalRenderSchemeBranch = {
279
+ type: Directive.If | Directive.ElseIf;
280
+ notation: ParsedNotation;
281
+ branchRootRef: string;
282
+ branchTemplateHTML: string;
283
+ } | {
284
+ type: Directive.Else;
285
+ branchRootRef: string;
286
+ branchTemplateHTML: string;
287
+ };
288
+ interface ConditionalRenderScheme {
289
+ type: "cond";
290
+ branches: ConditionalRenderSchemeBranch[];
291
+ }
292
+ interface AttributeUpdateScheme {
293
+ type: "attr";
294
+ notation: ParsedNotation;
295
+ attribute: string;
296
+ nodeRef: string;
297
+ }
298
+ interface TagChangeScheme {
299
+ type: "tag";
300
+ notation: ParsedNotation;
301
+ nodeRef: string;
302
+ }
303
+ interface ContentSwapScheme {
304
+ type: "swap";
305
+ notation: ParsedNotation;
306
+ nodeRef: string;
307
+ }
308
+ interface ListRenderScheme {
309
+ type: "each";
310
+ notation: ParsedNotation;
311
+ keyNotation: ParsedNotation;
312
+ nodeRef: string;
313
+ listContentHtml: string;
314
+ }
315
+ type AnyScheme = AttributeUpdateScheme | TagChangeScheme | ContentSwapScheme | ListRenderScheme | ConditionalRenderScheme;
316
+ /**
317
+ * A JSON-serializable representation of a {@link Template} instance, including
318
+ * everything needed to recreate the template.
319
+ */
320
+ interface CompiledTemplate {
321
+ html: string;
322
+ schemes: AnyScheme[];
323
+ notations: Record<string, ParsedNotation>;
324
+ }
276
325
  type TemplateRoot = HTMLElement | ShadowRoot;
277
326
  type TemplateContext = {
278
327
  attr?: Record<string, string | null>;
@@ -347,7 +396,10 @@ declare class Template {
347
396
  private _plansByNotation;
348
397
  /** Value Notations -> Accessor functions */
349
398
  private _notationAccessors;
399
+ private _subtemplates;
350
400
  constructor(template: HTMLTemplateElement);
401
+ get compiled(): CompiledTemplate;
402
+ get notationMap(): Map<string, NotationAccessor>;
351
403
  /**
352
404
  * Create a full copy of this template for use in rendering to another root
353
405
  */
@@ -358,6 +410,7 @@ declare class Template {
358
410
  element: () => HTMLTemplateElement;
359
411
  private _collectUpdatedValues;
360
412
  private _update;
413
+ renderWithValues: (root: TemplateRoot, values: Map<string, unknown>) => void;
361
414
  /**
362
415
  * Render this template into a target host element.
363
416
  */
@@ -375,31 +428,26 @@ type ComputedProperties<StateShape extends object = {}> = Record<string, unknown
375
428
  type ComponentStyles = CSSStyleSheet | CSSStyleSheet[] | string;
376
429
  type AttributeMap = Map<string, string | null>;
377
430
  type StateInitializer<Shape extends object = {}> = Shape | State<Shape> | ((this: Component<Shape>) => Shape | State<Shape>);
431
+ declare enum RootMode {
432
+ Closed = "closed",
433
+ Open = "open"
434
+ }
378
435
  /**
379
436
  * The **Component** class extends the base HTMLElement class to provide an
380
437
  * ergonomic way to design and develop Web Components with reactive state,
381
438
  * managed attributes, and dynamic templating.
382
439
  */
383
440
  declare abstract class Component<StateShape extends object = {}> extends HTMLElement {
384
- /**
385
- * Register a Component with the browser. Optionally provide an overriding
386
- * tag name.
387
- */
388
- static register(component: CustomElementConstructor | typeof Component, tagName?: string): void;
389
- /**
390
- * The HTML tag name to use for this Component
391
- */
441
+ /** The HTML tag name to use for this Component */
392
442
  static tagName: string;
393
- /**
394
- * An HTML Template element for this element to use.
395
- */
443
+ /** An HTML Template element for this element to use. */
396
444
  static template: HTMLTemplateElement | Template;
397
445
  /**
398
- * A {@link CSSStyleSheet} array or string to adopt as the component's scoped styles
446
+ * Styles for this Component
399
447
  */
400
448
  static styles: ComponentStyles;
401
449
  /**
402
- * An array of html attribute names to observe to trigger updates.
450
+ * A list of attribute names to track changes for
403
451
  *
404
452
  * @remarks
405
453
  * If you use the {@link define} factory helper, this value will be
@@ -407,39 +455,23 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
407
455
  */
408
456
  static observedAttributes: string[];
409
457
  /**
410
- * The mode for this Component's ShadowRoot.
411
- *
412
- * - `"open"` allows JS access to the children of this component
413
- * - `"closed"` (default) disallows internal JS access
458
+ * The mode for this Component's ShadowRoot. Must be a {@link RootMode}
414
459
  */
415
- static shadowRootMode: "closed" | "open";
460
+ static rootMode: RootMode;
416
461
  /**
417
- * Called immediately before each template update
462
+ * Initialization lifecycle method. Main scripting and event listeners.
463
+ * @returns a function to handle cleanup tasks when the component unmounts
418
464
  */
465
+ protected script?(): VoidFunction | void;
466
+ /** Called immediately before each template update */
419
467
  protected beforeUpdate?(): void;
420
- /**
421
- * Called immediately after each template update
422
- */
468
+ /** Called immediately after each template update */
423
469
  protected afterUpdate?(previousAttributes: AttributeMap): void;
424
- /**
425
- * Called as the final lifecycle method at the end of the unmounting process.
426
- *
427
- * Content has been removed from the DOM and the component is no longer
428
- * considered mounted when this function runs.
429
- *
430
- * Use this for final cleanup tasks and freeing resources.
431
- */
470
+ /** Final lifecycle method called at the end of the unmounting process. */
432
471
  protected finalize?(): void;
433
472
  /**
434
- * If defined, receives errors caught during the lifecycle methods of this
435
- * component and it's children. If not defined, this component will instead
436
- * throw errors as they are found.
437
- *
438
- * If the error cannot be handled, `onError()` should re-throw it for a higher
439
- * up component to evaluate.
440
- *
441
- * To display an error message while removing an erroring component from the
442
- * DOM, use `this.replaceWith()` and a newly constructed placeholder element.
473
+ * When defined, catches any errors thrown during lifecycle mthods of this
474
+ * component as well as any uncaught errors from child components.
443
475
  *
444
476
  * @example
445
477
  *
@@ -447,16 +479,12 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
447
479
  *
448
480
  * ```typescript
449
481
  * onError(error) {
450
- * // Handle known errors
451
- * if (error.message = "Invalid Input") {
452
- * this.state.input = "";
482
+ * if (error.canRecover) {
483
+ * this.recover();
453
484
  * return;
454
485
  * }
455
486
  *
456
- * // Display a fallback banner
457
- * const banner = document.createElement("div");
458
- * banner.textContent = "An unexpected error done did";
459
- * this.replaceWith(banner);
487
+ * this.replaceWith("Oh dear, an error happened real bad");
460
488
  * }
461
489
  * ```
462
490
  */
@@ -464,6 +492,7 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
464
492
  /**
465
493
  * The initial value for this Component's reactive internal state, if any.
466
494
  *
495
+ * @remarks
467
496
  * If `initialState` is defined as a function, the function is evaluated at
468
497
  * mounting time and the return value is used as the initial state.
469
498
  */
@@ -472,20 +501,6 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
472
501
  * An object or function returning an object which populates the `data` values
473
502
  * in the templating engine. Such values are accessed using the `*` notation.
474
503
  *
475
- * When a hosted value is accessed, it's value is coerced based on the way it
476
- * is being used. For attributes, values are serialized to a string or null,
477
- * which will set the attribute (string) or remove it (null).
478
- *
479
- * For content swaps, strings, numbers and booleans are rendered as strings
480
- * and set as textContent. null and undefined values render nothing (with a
481
- * comment placeholder), an HTMLElement will be swapped in as a cloned node.
482
- *
483
- * Functions are evaluated at render/update time, and their return value is
484
- * used instead. Functions are passed the current target node accessing the
485
- * property as its first and only argument.
486
- *
487
- * Other types are unsupported.
488
- *
489
504
  * @example
490
505
  *
491
506
  * ```typescript
@@ -502,17 +517,8 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
502
517
  */
503
518
  protected computedProperties?: ComputedProperties<StateShape>;
504
519
  /**
505
- * Declaration of attribute behaviors during updates.
506
- *
507
- * Each key is the name of an attribute. Values are an object with two
508
- * optional function definitions:
509
- *
510
- * `onChange(newValue, oldValue): void`, a handler function for when the value
511
- * of this attribute has changed. Runs once per update cycle, *before* the
512
- * update occurs.
513
- *
514
- * `reflect(): unknown`, a function which returns a value to serialize and set
515
- * as this attribute *after* an update completes.
520
+ * Define attribute update and reflection behaviors as a record of attribute
521
+ * name keys to objects with optionally defined behaviors.
516
522
  *
517
523
  * @example
518
524
  *
@@ -528,22 +534,24 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
528
534
  * ```
529
535
  *
530
536
  * @remarks
537
+ * The optional functions are:
538
+ *
539
+ * `onChange(newValue, oldValue): void`, a handler function for when the value
540
+ * of this attribute has changed. Runs once per update cycle, *before* the
541
+ * update occurs.
542
+ *
543
+ * `reflect(): unknown`, a function which returns a value to serialize and set
544
+ * as this attribute *after* an update completes.
531
545
  *
532
546
  * If using the {@link define} helper, the keys of this property are
533
547
  * automatically merged with any defined {@link observedAttributes}.
534
- *
535
- * If you are directly extending the class, `observedAttributes` must be
536
- * explicitly defined with any attributes that should be monitored, regardless
537
- * of if they're defined here.
538
548
  */
539
549
  protected liveAttributes?: LiveAttributes<StateShape>;
540
- private _isComponentMounted;
541
550
  private _template;
542
551
  private _root;
543
552
  private _state?;
544
553
  private _delegator?;
545
- private _ownListeners;
546
- private _liveAttributeConfigs;
554
+ private _ownListeners?;
547
555
  private _cleanupFn?;
548
556
  private _renderInternals;
549
557
  constructor();
@@ -574,86 +582,29 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
574
582
  * The ShadowRoot node of this element
575
583
  */
576
584
  get root(): ShadowRoot;
585
+ get isMounted(): boolean;
577
586
  /**
578
- * Directly access and manipulate this Component's reactive state with deep
579
- * reactivity enabled.
580
- *
581
- * @example
582
- *
583
- * ```typescript
584
- * initialState = { values: { count: 1, time: 0 } };
585
- *
586
- * increment() {
587
- * this.state.values.count = 2;
588
- * }
589
- * ```
587
+ * Accessor for live reactive state.
590
588
  *
591
- * @remarks
592
- * This is a shorthand getter for `this.getState().live`
589
+ * For the full state manipulation API, use {@link getState}
593
590
  */
594
591
  get state(): StateShape;
595
592
  /**
596
593
  * Replace the current state with a new value or adopt a whole different State
597
594
  * instance
598
- *
599
- * @example
600
- *
601
- * State replacement
602
- *
603
- * ```typescript
604
- * // Always triggers a render
605
- * this.state = { some: "newState" }
606
- *
607
- * // Adopt a new state instance altogether
608
- * const otherState = new State({some: "newState"});
609
- * this.state = otherState;
610
- *
611
- * // Causes a render
612
- * otherState.set("some", "value");
613
- * ```
614
595
  */
615
596
  set state(newState: StateShape | State<StateShape>);
616
597
  /**
617
598
  * Access the full {@link State} instance for this Component.
618
599
  *
619
- * Using this method on a component which is not using reactive state
600
+ * @remarks
601
+ * Calling this method on a component which is not using reactive state
620
602
  * will result in an error being thrown.
621
- *
622
- * @example
623
- *
624
- * Retrieve stateful value
625
- *
626
- * ```typescript
627
- * class Example extends Component {
628
- * initialState = { count: 1 };
629
- *
630
- * script() {
631
- * const state = this.getState();
632
- * console.log(`The count is ${state.get("count")}`);
633
- * }
634
- *
635
- * }
636
- * ```
637
- *
638
- * @example
639
- *
640
- * Set a stateful value
641
- *
642
- * ```typescript
643
- * class Example extends Component {
644
- * initialState = { count: 1 };
645
- *
646
- * increment() {
647
- * const state = this.getState();
648
- * const current = state.get("count");
649
- * state.set("count", current + 1);
650
- * }
651
- * }
652
- * ```
653
603
  */
654
604
  getState(): State<StateShape>;
655
605
  /**
656
- * Manually schedule a render to occur
606
+ * Manually schedule a render to occur, optionally providing a callback to
607
+ * invoke after the render completes.
657
608
  *
658
609
  * @remarks
659
610
  * Calling {@link requestRender} multiple times in the same event loop won't
@@ -662,57 +613,19 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
662
613
  */
663
614
  requestRender(callback?: VoidFunction): void;
664
615
  /**
665
- * Create a managed event listener on this Component with an optional query
666
- * filter string to specify which elements to listen to events from.
667
- *
668
- * Event handlers set up with `listen()` are automatically cleaned up when
669
- * the component is unmounted.
670
- *
671
- * Handlers are delegated to a single listener per event on the root of the
672
- * Component, which is the closed ShadowRoot by default.
673
- *
674
- * @example
675
- *
676
- * Set up an event listener for a click event from a button with ID "submit"
677
- *
678
- * ```typescript
679
- * this.listen("#submit", "click", this.handleClick);
680
- * ```
681
- *
682
- * @example
616
+ * Listen for events from within this Component.
683
617
  *
684
- * Set up an event listener on the host element itself (`this`).
618
+ * Provide a query string to target specific element events, or use `:host`
619
+ * to create listeners on the host element itself.
685
620
  *
686
- * ```typescript
687
- * // Use ":host" or ":HOST" as the query selector to targe the host element
688
- * this.listen(":host", "animationend", this.handler);
689
- * ```
621
+ * Event listeners created with this method are automatically cleaned up when
622
+ * the component unmounts.
690
623
  */
691
624
  listen<E extends EventName>(targetDescriptor: string | typeof Component<any> | HTMLElement, eventName: E, eventHandler: EventHandler<E>): void;
692
625
  stopListening<E extends EventName>(targetDescriptor: string | typeof Component<any> | HTMLElement, eventName: E, eventHandler: EventHandler<E>): void;
693
626
  dispatchEvent(event: Event): boolean;
694
627
  /**
695
628
  * Dispatch a {@link CustomEvent} with the specified name and detail
696
- *
697
- * @example Defining custom events
698
- *
699
- * ```typescript
700
- * // Define types. This can happen in the same file or elsewhere for common
701
- * // and shared events.
702
- * type MyEvent = CustomEvent<T> // Set `T` to the event detail type
703
- *
704
- * declare global {
705
- * interface GlobalEventHandlersEventMap {
706
- * "my-event-name": MyEvent
707
- * }
708
- * }
709
- *
710
- * // Dispatch a custom event
711
- * this.dispatchEvent("my-event-name", T);
712
- *
713
- * // Listen to a custom event
714
- * $el.addEventListener("my-event-name", ...);
715
- * ```
716
629
  */
717
630
  dispatchEvent<T>(event: string, detail?: T, options?: {
718
631
  bubbles: boolean;
@@ -734,11 +647,8 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
734
647
  /**
735
648
  * Get an attribute as a number, falling back to a specified default.
736
649
  *
737
- *
738
650
  * `null` attributes are returned as `null`, while string attributes are
739
- * parsed using the `Number()` constructor.
740
- *
741
- * Values which evaluate to NaN are returned as `null`.
651
+ * parsed using the `Number()` constructor. NaN is coerced to `null`.
742
652
  */
743
653
  getAttribute(name: string, defaultValue: number): number;
744
654
  /**
@@ -753,7 +663,7 @@ declare abstract class Component<StateShape extends object = {}> extends HTMLEle
753
663
  /**
754
664
  * Serialize this element to a string
755
665
  */
756
- toString(full?: boolean): string;
666
+ toString(): string;
757
667
  }
758
668
  interface ComponentShorthand<StateShape extends object = {}> {
759
669
  /**
@@ -798,46 +708,40 @@ interface ComponentShorthand<StateShape extends object = {}> {
798
708
  afterUpdate?: (this: Component<StateShape>, previousAttributes: AttributeMap) => void;
799
709
  /**
800
710
  * Called as the final lifecycle method at the end of the unmounting process.
801
- *
802
- * Content has been removed from the DOM and the component is no longer
803
- * considered mounted when this function runs.
804
- *
805
- * Use this for final cleanup tasks and freeing resources.
806
711
  */
807
712
  finalize?: (this: Component<StateShape>) => void;
808
713
  /**
809
714
  * If defined, receives errors caught during the lifecycle methods of this
810
715
  * component and it's children. If not defined, this component will instead
811
716
  * throw errors as they are found.
812
- *
813
- * If the error cannot be handled, `onError()` should re-throw it for a higher
814
- * up component to evaluate.
815
- *
816
- * To display an error message while removing an erroring component from the
817
- * DOM, use `this.replaceWith()` and a newly constructed placeholder element.
818
- *
819
- * @example
820
- *
821
- * Recovering from errors or displaying a fallback
822
- *
823
- * ```typescript
824
- * onError(error) {
825
- * // Handle known errors
826
- * if (error.message = "Invalid Input") {
827
- * this.state.input = "";
828
- * return;
829
- * }
830
- *
831
- * // Display a fallback banner
832
- * const banner = document.createElement("div");
833
- * banner.textContent = "An unexpected error done did";
834
- * this.replaceWith(banner);
835
- * }
836
- * ```
837
717
  */
838
718
  onError?: (this: Component<StateShape>, error: unknown) => void;
839
719
  }
840
- declare function define<StateShape extends object = {}>(tagname: string, definition: ComponentShorthand<StateShape>): typeof Component<StateShape>;
720
+ /**
721
+ * Register a Palette Component as a custom element
722
+ */
723
+ declare function define<Cls extends typeof Component<any>>(definition: Cls): Cls;
724
+ /**
725
+ * Register a Palette Component as a custom element
726
+ */
727
+ declare function define<Cls extends typeof Component<any>>(tagName: string, definition: Cls): Cls;
728
+ /**
729
+ * Define a Palette Component using the shorthand syntax
730
+ *
731
+ * @example
732
+ *
733
+ * ```typescript
734
+ * define("my-component", {
735
+ * template: html`...`,
736
+ * styles: css`...`,
737
+ * initialState: { ... },
738
+ * computedProperties() { ... },
739
+ * script() { ... },
740
+ * // and any other lifecycle methods
741
+ * });
742
+ * ```
743
+ */
744
+ declare function define<StateShape extends object = {}>(tagName: string, definition: ComponentShorthand<StateShape>): typeof Component<StateShape>;
841
745
  /**
842
746
  * An error originating from within a Palette subsystem.
843
747
  *
@@ -862,7 +766,7 @@ declare class PaletteError extends Error {
862
766
  /**
863
767
  * @returns An array of {@link CSSStyleSheet}s containing the provided CSS
864
768
  */
865
- declare function css(strings: TemplateStringsArray, ...values: unknown[]): CSSStyleSheet;
769
+ declare function css(strings: TemplateStringsArray, ...values: (string | typeof Component<any>)[]): CSSStyleSheet;
866
770
  type ClassValue = string | number | boolean | undefined | null | ClassArray | ClassObject;
867
771
  type ClassArray = ClassValue[];
868
772
  type ClassObject = Record<string, any>;
@@ -914,4 +818,4 @@ declare function classify(...args: ClassValue[]): string;
914
818
  * ```
915
819
  */
916
820
  declare function html(strings: TemplateStringsArray, ...values: (`@${string}` | `$${string}` | `#${string}` | `*${string}` | HTMLTemplateElement | typeof Component<any>)[]): HTMLTemplateElement;
917
- export { html, define, css, classify, TemplateRoot, TemplateContext, Template, StateListener, StateInitializer, State, PaletteError, LiveAttributes, EventName, EventHandler, ComputedProperties, ComponentStyles, ComponentShorthand, Component, AttributeMap };
821
+ export { html, define, css, classify, TemplateRoot, TemplateContext, Template, StateListener, StateInitializer, State, RootMode, PaletteError, LiveAttributes, EventName, EventHandler, ComputedProperties, ComponentStyles, ComponentShorthand, Component, AttributeMap };