element-vir 5.6.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +97 -93
  2. package/dist/augments/testing.d.ts +15 -0
  3. package/dist/augments/testing.js +76 -0
  4. package/dist/augments/type.d.ts +7 -0
  5. package/dist/augments/type.js +13 -1
  6. package/dist/{functional-element → declarative-element}/css-vars.d.ts +0 -0
  7. package/dist/{functional-element → declarative-element}/css-vars.js +0 -0
  8. package/dist/declarative-element/declarative-element-init.d.ts +33 -0
  9. package/dist/declarative-element/declarative-element-init.js +1 -0
  10. package/dist/declarative-element/declarative-element.d.ts +44 -0
  11. package/dist/declarative-element/declarative-element.js +18 -0
  12. package/dist/declarative-element/define-element-no-inputs.d.ts +5 -0
  13. package/dist/declarative-element/define-element-no-inputs.js +118 -0
  14. package/dist/declarative-element/define-element.d.ts +5 -0
  15. package/dist/declarative-element/define-element.js +13 -0
  16. package/dist/declarative-element/definition-options.d.ts +5 -0
  17. package/dist/declarative-element/definition-options.js +4 -0
  18. package/dist/declarative-element/directives/assign-with-clean-up.directive.d.ts +23 -0
  19. package/dist/declarative-element/directives/assign-with-clean-up.directive.js +43 -0
  20. package/dist/declarative-element/directives/assign.directive.d.ts +12 -0
  21. package/dist/declarative-element/directives/assign.directive.js +35 -0
  22. package/dist/{functional-element/directives/directive-util.d.ts → declarative-element/directives/directive-helpers.d.ts} +2 -3
  23. package/dist/{functional-element/directives/directive-util.js → declarative-element/directives/directive-helpers.js} +4 -4
  24. package/dist/{functional-element → declarative-element}/directives/listen.directive.d.ts +2 -2
  25. package/dist/{functional-element → declarative-element}/directives/listen.directive.js +1 -1
  26. package/dist/{functional-element → declarative-element}/directives/on-dom-created.directive.d.ts +0 -0
  27. package/dist/{functional-element → declarative-element}/directives/on-dom-created.directive.js +1 -1
  28. package/dist/{functional-element → declarative-element}/directives/on-resize.directive.d.ts +0 -0
  29. package/dist/{functional-element → declarative-element}/directives/on-resize.directive.js +1 -1
  30. package/dist/{functional-element → declarative-element}/element-events.d.ts +0 -0
  31. package/dist/{functional-element → declarative-element}/element-events.js +1 -1
  32. package/dist/{functional-element → declarative-element}/element-properties.d.ts +3 -3
  33. package/dist/declarative-element/element-properties.js +53 -0
  34. package/dist/declarative-element/has-declarative-element-parent.d.ts +1 -0
  35. package/dist/declarative-element/has-declarative-element-parent.js +16 -0
  36. package/dist/declarative-element/host-classes.d.ts +21 -0
  37. package/dist/{functional-element → declarative-element}/host-classes.js +0 -0
  38. package/dist/declarative-element/render-callback.d.ts +22 -0
  39. package/dist/{functional-element → declarative-element}/render-callback.js +4 -3
  40. package/dist/{functional-element → declarative-element}/styles.d.ts +7 -1
  41. package/dist/{functional-element → declarative-element}/styles.js +2 -2
  42. package/dist/{functional-element → declarative-element}/tag-name.d.ts +0 -0
  43. package/dist/{functional-element → declarative-element}/tag-name.js +0 -0
  44. package/dist/declarative-element-marker-symbol.d.ts +1 -0
  45. package/dist/declarative-element-marker-symbol.js +1 -0
  46. package/dist/index.d.ts +14 -12
  47. package/dist/index.js +13 -12
  48. package/dist/require-declarative-element.d.ts +2 -0
  49. package/dist/require-declarative-element.js +4 -0
  50. package/dist/template-transforms/nested-mapped-templates.d.ts +6 -0
  51. package/dist/template-transforms/nested-mapped-templates.js +96 -0
  52. package/dist/template-transforms/transform-template.js +21 -2
  53. package/dist/template-transforms/vir-css/css-transform.d.ts +2 -2
  54. package/dist/template-transforms/vir-css/vir-css.d.ts +2 -2
  55. package/dist/template-transforms/vir-css/vir-css.js +1 -1
  56. package/dist/template-transforms/vir-html/html-transform.js +3 -3
  57. package/dist/template-transforms/vir-html/vir-html.d.ts +1 -1
  58. package/dist/template-transforms/vir-html/vir-html.js +1 -1
  59. package/index.html +14 -0
  60. package/package.json +14 -14
  61. package/public/index.css +7 -0
  62. package/dist/functional-element/define-functional-element.d.ts +0 -4
  63. package/dist/functional-element/define-functional-element.js +0 -70
  64. package/dist/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
  65. package/dist/functional-element/directives/assign-with-clean-up.directive.js +0 -36
  66. package/dist/functional-element/directives/assign.directive.d.ts +0 -15
  67. package/dist/functional-element/directives/assign.directive.js +0 -23
  68. package/dist/functional-element/element-properties.js +0 -50
  69. package/dist/functional-element/functional-element.d.ts +0 -57
  70. package/dist/functional-element/functional-element.js +0 -3
  71. package/dist/functional-element/host-classes.d.ts +0 -19
  72. package/dist/functional-element/render-callback.d.ts +0 -21
  73. package/dist/require-functional-element.d.ts +0 -2
  74. package/dist/require-functional-element.js +0 -4
@@ -0,0 +1,18 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement } from 'lit';
8
+ function staticImplements() {
9
+ return (constructor) => {
10
+ constructor;
11
+ };
12
+ }
13
+ let DeclarativeElement = class DeclarativeElement extends LitElement {
14
+ };
15
+ DeclarativeElement = __decorate([
16
+ staticImplements()
17
+ ], DeclarativeElement);
18
+ export { DeclarativeElement };
@@ -0,0 +1,5 @@
1
+ import { DeclarativeElementDefinition } from './declarative-element';
2
+ import { DeclarativeElementInit } from './declarative-element-init';
3
+ import { EventsInitMap } from './element-events';
4
+ import { PropertyInitMapBase } from './element-properties';
5
+ export declare function defineElementNoInputs<InputsGeneric extends PropertyInitMapBase = {}, StateGeneric extends PropertyInitMapBase = {}, EventsInitGeneric extends EventsInitMap = {}, HostClassKeys extends string = '', CssVarKeys extends string = ''>(initInput: DeclarativeElementInit<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>): DeclarativeElementDefinition<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
@@ -0,0 +1,118 @@
1
+ import { kebabCaseToCamelCase } from 'augment-vir';
2
+ import { css } from 'lit';
3
+ import { property } from 'lit/decorators.js';
4
+ import { DeclarativeElementMarkerSymbol } from '../declarative-element-marker-symbol';
5
+ import { createCssVarNamesMap, createCssVarValuesMap } from './css-vars';
6
+ import { DeclarativeElement, } from './declarative-element';
7
+ import { defaultDeclarativeElementDefinitionOptions, IgnoreInputsNotBeenSetBeforeRenderWarningSymbol, } from './definition-options';
8
+ import { assign } from './directives/assign.directive';
9
+ import { createEventDescriptorMap } from './element-events';
10
+ import { createElementUpdaterProxy } from './element-properties';
11
+ import { hasDeclarativeElementParent } from './has-declarative-element-parent';
12
+ import { createHostClassNamesMap } from './host-classes';
13
+ import { createRenderParams } from './render-callback';
14
+ import { applyHostClasses, hostClassNamesToStylesInput } from './styles';
15
+ export function defineElementNoInputs(initInput) {
16
+ var _a;
17
+ const eventsMap = createEventDescriptorMap(initInput.events);
18
+ const hostClassNames = createHostClassNamesMap(initInput.tagName, initInput.hostClasses);
19
+ const cssVarNames = createCssVarNamesMap(initInput.tagName, initInput.cssVars);
20
+ const cssVarValues = createCssVarValuesMap(initInput.cssVars, cssVarNames);
21
+ const elementOptions = {
22
+ ...defaultDeclarativeElementDefinitionOptions,
23
+ ...initInput.options,
24
+ };
25
+ const calculatedStyles = typeof initInput.styles === 'function'
26
+ ? initInput.styles(hostClassNamesToStylesInput({ hostClassNames, cssVarNames, cssVarValues }))
27
+ : initInput.styles || css ``;
28
+ const typedRenderCallback = initInput.renderCallback;
29
+ const anonymousClass = (_a = class extends DeclarativeElement {
30
+ constructor() {
31
+ super();
32
+ this.initCalled = false;
33
+ this.haveInputsBeenSet = false;
34
+ // this is set below in Object.defineProperties
35
+ this.creator = {};
36
+ this.instanceInputs = createElementUpdaterProxy(this, false);
37
+ this.instanceState = createElementUpdaterProxy(this, true);
38
+ const stateInit = initInput.stateInit || {};
39
+ Object.keys(stateInit).forEach((propName) => {
40
+ property()(this, propName);
41
+ this[propName] = stateInit[propName];
42
+ });
43
+ }
44
+ createRenderParams() {
45
+ return createRenderParams(this, eventsMap);
46
+ }
47
+ get instanceType() {
48
+ throw new Error(`"instanceType" was called on ${initInput.tagName} as a value but it is only for types.`);
49
+ }
50
+ static get inputsType() {
51
+ throw new Error(`"inputsType" was called on ${initInput.tagName} as a value but it is only for types.`);
52
+ }
53
+ markInputsAsHavingBeenSet() {
54
+ if (!this.haveInputsBeenSet) {
55
+ this.haveInputsBeenSet = true;
56
+ }
57
+ }
58
+ render() {
59
+ if (
60
+ // This ignores elements at the root of a page, as they can't receive inputs from
61
+ // other elements (cause they have no custom element ancestors).
62
+ hasDeclarativeElementParent(this) &&
63
+ !this.haveInputsBeenSet &&
64
+ !elementOptions[IgnoreInputsNotBeenSetBeforeRenderWarningSymbol]) {
65
+ console.warn(this, `${initInput.tagName} got rendered before its input object was set. This was most likely caused by forgetting to use the "${assign.name}" directive on it. If no inputs are intended, use "${defineElementNoInputs.name}" to define ${initInput.tagName}.`);
66
+ }
67
+ const renderParams = this.createRenderParams();
68
+ if (!this.initCalled && initInput.initCallback) {
69
+ this.initCalled = true;
70
+ initInput.initCallback(renderParams);
71
+ }
72
+ const renderResult = initInput.renderCallback(renderParams);
73
+ applyHostClasses({
74
+ host: renderParams.host,
75
+ hostClassesInit: initInput.hostClasses,
76
+ hostClassNames,
77
+ state: renderParams.state,
78
+ inputs: renderParams.inputs,
79
+ });
80
+ return renderResult;
81
+ }
82
+ },
83
+ _a.tagName = initInput.tagName,
84
+ _a.styles = calculatedStyles,
85
+ // this gets set below in Object.defineProperties
86
+ _a.isStrictInstance = () => false,
87
+ _a.events = eventsMap,
88
+ _a.renderCallback = typedRenderCallback,
89
+ _a.hostClasses = hostClassNames,
90
+ _a.cssVarNames = cssVarNames,
91
+ _a.stateInit = initInput.stateInit,
92
+ _a.cssVarValues = cssVarNames,
93
+ _a);
94
+ Object.defineProperties(anonymousClass, {
95
+ [DeclarativeElementMarkerSymbol]: {
96
+ value: true,
97
+ writable: false,
98
+ },
99
+ name: {
100
+ value: kebabCaseToCamelCase(initInput.tagName, {
101
+ capitalizeFirstLetter: true,
102
+ }),
103
+ writable: true,
104
+ },
105
+ creator: {
106
+ value: anonymousClass,
107
+ writable: false,
108
+ },
109
+ isStrictInstance: {
110
+ value: (element) => {
111
+ return element instanceof anonymousClass;
112
+ },
113
+ writable: false,
114
+ },
115
+ });
116
+ window.customElements.define(initInput.tagName, anonymousClass);
117
+ return anonymousClass;
118
+ }
@@ -0,0 +1,5 @@
1
+ import { DeclarativeElementDefinition } from './declarative-element';
2
+ import { DeclarativeElementInit } from './declarative-element-init';
3
+ import { EventsInitMap } from './element-events';
4
+ import { PropertyInitMapBase } from './element-properties';
5
+ export declare function defineElement<InputsGeneric extends PropertyInitMapBase = {}>(): <PropertyInitGeneric extends PropertyInitMapBase = {}, EventsInitGeneric extends EventsInitMap = {}, HostClassKeys extends string = "", CssVarKeys extends string = "">(initInput: DeclarativeElementInit<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) => DeclarativeElementDefinition<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
@@ -0,0 +1,13 @@
1
+ import { defineElementNoInputs } from './define-element-no-inputs';
2
+ import { IgnoreInputsNotBeenSetBeforeRenderWarningSymbol } from './definition-options';
3
+ export function defineElement() {
4
+ return (initInput) => {
5
+ return defineElementNoInputs({
6
+ ...initInput,
7
+ options: {
8
+ [IgnoreInputsNotBeenSetBeforeRenderWarningSymbol]: false,
9
+ },
10
+ ...initInput.options,
11
+ });
12
+ };
13
+ }
@@ -0,0 +1,5 @@
1
+ export declare const IgnoreInputsNotBeenSetBeforeRenderWarningSymbol: unique symbol;
2
+ export declare type DeclarativeElementDefinitionOptions = {
3
+ [IgnoreInputsNotBeenSetBeforeRenderWarningSymbol]: boolean;
4
+ };
5
+ export declare const defaultDeclarativeElementDefinitionOptions: DeclarativeElementDefinitionOptions;
@@ -0,0 +1,4 @@
1
+ export const IgnoreInputsNotBeenSetBeforeRenderWarningSymbol = Symbol('key for ignoring inputs not having been set yet');
2
+ export const defaultDeclarativeElementDefinitionOptions = {
3
+ [IgnoreInputsNotBeenSetBeforeRenderWarningSymbol]: true,
4
+ };
@@ -0,0 +1,23 @@
1
+ import { AsyncDirective } from 'lit/async-directive.js';
2
+ import { PartInfo } from 'lit/directive.js';
3
+ import { DeclarativeElementDefinition } from '../declarative-element';
4
+ export declare type CleanupCallback<T> = (oldValue: T) => void;
5
+ /**
6
+ * Assign values but include a cleanup callback which gets called when a new value gets assigned so
7
+ * the previous value can get cleaned up. An optional equality check callback can be provided. If it
8
+ * is provided, the clean up callback will then only be called if the equality check callback
9
+ * resolves to false (which indicates that the previous value and the new value are not equal).
10
+ *
11
+ * Example use case: 3D graphics applications with classes that setup buffers and the like.
12
+ */
13
+ export declare function assignWithCleanup<DeclarativeElementGeneric extends DeclarativeElementDefinition>(elementDefinition: DeclarativeElementGeneric, inputsObject: DeclarativeElementGeneric extends DeclarativeElementDefinition<infer InputsGeneric> ? InputsGeneric : never, cleanupCallback: CleanupCallback<DeclarativeElementGeneric extends DeclarativeElementDefinition<infer InputsGeneric> ? InputsGeneric : never>): import("lit-html/directive").DirectiveResult<typeof AssignWithCleanupDirectiveClass>;
14
+ declare class AssignWithCleanupDirectiveClass extends AsyncDirective {
15
+ private readonly element;
16
+ private lastValue;
17
+ private lastCallback;
18
+ private hasBeenAssigned;
19
+ constructor(partInfo: PartInfo);
20
+ disconnected(): void;
21
+ render(elementDefinition: DeclarativeElementDefinition, inputsObject: Record<PropertyKey, unknown>, cleanupCallback: CleanupCallback<any>): symbol;
22
+ }
23
+ export {};
@@ -0,0 +1,43 @@
1
+ import { noChange } from 'lit';
2
+ import { AsyncDirective } from 'lit/async-directive.js';
3
+ import { directive } from 'lit/directive.js';
4
+ import { assignInputsObject } from './assign.directive';
5
+ import { extractDeclarativeElement } from './directive-helpers';
6
+ /**
7
+ * Assign values but include a cleanup callback which gets called when a new value gets assigned so
8
+ * the previous value can get cleaned up. An optional equality check callback can be provided. If it
9
+ * is provided, the clean up callback will then only be called if the equality check callback
10
+ * resolves to false (which indicates that the previous value and the new value are not equal).
11
+ *
12
+ * Example use case: 3D graphics applications with classes that setup buffers and the like.
13
+ */
14
+ export function assignWithCleanup(elementDefinition, inputsObject, cleanupCallback) {
15
+ /**
16
+ * The directive generics (in listenDirective) are not strong enough to maintain their values.
17
+ * Thus, the directive call is wrapped in this function.
18
+ */
19
+ return assignWithCleanupDirective(elementDefinition, inputsObject, cleanupCallback);
20
+ }
21
+ class AssignWithCleanupDirectiveClass extends AsyncDirective {
22
+ constructor(partInfo) {
23
+ super(partInfo);
24
+ this.hasBeenAssigned = false;
25
+ this.element = extractDeclarativeElement(partInfo, 'assign');
26
+ }
27
+ disconnected() {
28
+ if (this.lastValue != undefined && this.lastCallback != undefined) {
29
+ this.lastCallback(this.lastValue);
30
+ }
31
+ }
32
+ render(elementDefinition, inputsObject, cleanupCallback) {
33
+ if (this.hasBeenAssigned) {
34
+ cleanupCallback(this.lastValue);
35
+ }
36
+ assignInputsObject(elementDefinition, this.element, inputsObject);
37
+ this.hasBeenAssigned = true;
38
+ this.lastValue = inputsObject;
39
+ this.lastCallback = cleanupCallback;
40
+ return noChange;
41
+ }
42
+ }
43
+ const assignWithCleanupDirective = directive(AssignWithCleanupDirectiveClass);
@@ -0,0 +1,12 @@
1
+ import { PartInfo } from 'lit/directive.js';
2
+ import { DeclarativeElement, DeclarativeElementDefinition } from '../declarative-element';
3
+ /** Assign an object matching an element's inputs to its inputs. */
4
+ export declare function assign<DeclarativeElementGeneric extends DeclarativeElementDefinition>(declarativeElement: DeclarativeElementGeneric, inputsObject: DeclarativeElementGeneric['inputsType']): import("lit-html/directive").DirectiveResult<{
5
+ new (partInfo: PartInfo): {
6
+ readonly element: DeclarativeElement<any, any, any, string, string>;
7
+ render(elementDefinition: DeclarativeElementDefinition<any, any, any, string, string>, inputsObject: Record<PropertyKey, unknown>): symbol;
8
+ readonly _$isConnected: boolean;
9
+ update(_part: import("lit-html").Part, props: unknown[]): unknown;
10
+ };
11
+ }>;
12
+ export declare function assignInputsObject<DeclarativeElementInstanceGeneric extends DeclarativeElement, DeclarativeElementDefinitionGeneric extends DeclarativeElementDefinition>(expectedElementConstructor: DeclarativeElementDefinitionGeneric, element: DeclarativeElementInstanceGeneric, assignmentObject: DeclarativeElementDefinitionGeneric['inputsType']): void;
@@ -0,0 +1,35 @@
1
+ import { noChange } from 'lit';
2
+ import { property } from 'lit/decorators.js';
3
+ import { directive, Directive } from 'lit/directive.js';
4
+ import { extractDeclarativeElement } from './directive-helpers';
5
+ /** Assign an object matching an element's inputs to its inputs. */
6
+ export function assign(declarativeElement, inputsObject) {
7
+ /**
8
+ * The directive generics (in listenDirective) are not strong enough to maintain their values.
9
+ * Thus, the directive call is wrapped in this function.
10
+ */
11
+ return assignDirective(declarativeElement, inputsObject);
12
+ }
13
+ const assignDirective = directive(class extends Directive {
14
+ constructor(partInfo) {
15
+ super(partInfo);
16
+ this.element = extractDeclarativeElement(partInfo, 'assign');
17
+ }
18
+ render(elementDefinition, inputsObject) {
19
+ assignInputsObject(elementDefinition, this.element, inputsObject);
20
+ return noChange;
21
+ }
22
+ });
23
+ export function assignInputsObject(expectedElementConstructor, element, assignmentObject) {
24
+ if (element.tagName.toLowerCase() !== expectedElementConstructor.tagName.toLowerCase()) {
25
+ console.error(element, expectedElementConstructor);
26
+ throw new Error(`Assignment mismatch. Assignment was made for ${element.tagName.toLowerCase()} but it's attached to ${expectedElementConstructor.tagName.toLowerCase()}`);
27
+ }
28
+ Object.keys(assignmentObject).forEach((key) => {
29
+ if (!element.constructor.elementProperties.has(key)) {
30
+ property()(element, key);
31
+ }
32
+ element.instanceInputs[key] = assignmentObject[key];
33
+ });
34
+ element.markInputsAsHavingBeenSet();
35
+ }
@@ -1,6 +1,5 @@
1
1
  import { ElementPartInfo, PartInfo } from 'lit/directive.js';
2
- import { PropertyInitMapBase } from '../element-properties';
3
- import { FunctionalElementInstanceFromInit } from '../functional-element';
2
+ import { DeclarativeElement } from '../declarative-element';
4
3
  /** For some reason these aren't defined in lit's types already. */
5
4
  export declare type ExtraPartInfoProperties = {
6
5
  element: Element;
@@ -10,6 +9,6 @@ export declare type ExtraPartInfoProperties = {
10
9
  isConnected: boolean;
11
10
  };
12
11
  };
13
- export declare function extractFunctionalElement<PropertyInitGeneric extends PropertyInitMapBase>(partInfo: PartInfo, directiveName: string): FunctionalElementInstanceFromInit<PropertyInitGeneric>;
12
+ export declare function extractDeclarativeElement(partInfo: PartInfo, directiveName: string): DeclarativeElement;
14
13
  export declare function extractElement<ElementType = HTMLElement>(partInfo: PartInfo, directiveName: string, constructorClass: (new () => ElementType) | (abstract new () => ElementType)): ElementType;
15
14
  export declare function assertsIsElementPartInfo(partInfo: PartInfo, directiveName: string): asserts partInfo is ElementPartInfo & ExtraPartInfoProperties;
@@ -1,7 +1,7 @@
1
1
  import { PartType } from 'lit/directive.js';
2
- import { FunctionalElementBaseClass } from '../functional-element';
3
- export function extractFunctionalElement(partInfo, directiveName) {
4
- return extractElement(partInfo, directiveName, FunctionalElementBaseClass);
2
+ import { DeclarativeElement } from '../declarative-element';
3
+ export function extractDeclarativeElement(partInfo, directiveName) {
4
+ return extractElement(partInfo, directiveName, DeclarativeElement);
5
5
  }
6
6
  export function extractElement(partInfo, directiveName, constructorClass) {
7
7
  assertsIsElementPartInfo(partInfo, directiveName);
@@ -16,6 +16,6 @@ export function assertsIsElementPartInfo(partInfo, directiveName) {
16
16
  throw new Error(`${directiveName} directive can only be attached directly to an element.`);
17
17
  }
18
18
  if (!partInfo.element) {
19
- throw new Error(`${directiveName} directive found no element`);
19
+ throw new Error(`${directiveName} directive found no element.`);
20
20
  }
21
21
  }
@@ -4,8 +4,8 @@ import { DefinedTypedEvent, TypedEvent } from '../../typed-event/typed-event';
4
4
  * Listen to events. These can be native DOM events (use a string for the inputType argument) or
5
5
  * typed events (pass in a return value from defineTypedEvent).
6
6
  *
7
- * @param definedTypedEvent Needs to come either from a functional element (like
8
- * MyFunctionalElement.events.eventName) or from a typed event created via the defineTypedEvent function.
7
+ * @param definedTypedEvent Needs to come either from a declarative element (like
8
+ * MyDeclarativeElement.events.eventName) or from a typed event created via the defineTypedEvent function.
9
9
  * @param listener The callback to fire when an event is caught. Assuming the definedTypedEvent
10
10
  * input is properly typed, the event given to this callback will also be typed.
11
11
  */
@@ -1,6 +1,6 @@
1
1
  import { noChange } from 'lit';
2
2
  import { directive, Directive } from 'lit/directive.js';
3
- import { extractElement } from './directive-util';
3
+ import { extractElement } from './directive-helpers';
4
4
  export function listen(eventType, listener) {
5
5
  return listenDirective(eventType, listener);
6
6
  }
@@ -1,5 +1,5 @@
1
1
  import { directive, Directive } from 'lit/directive.js';
2
- import { assertsIsElementPartInfo } from './directive-util';
2
+ import { assertsIsElementPartInfo } from './directive-helpers';
3
3
  const directiveName = 'onDomCreated';
4
4
  /** Only fires once, when the element has been created. */
5
5
  export const onDomCreated = directive(class extends Directive {
@@ -1,5 +1,5 @@
1
1
  import { directive, Directive } from 'lit/directive.js';
2
- import { assertsIsElementPartInfo } from './directive-util';
2
+ import { assertsIsElementPartInfo } from './directive-helpers';
3
3
  const directiveName = 'onResize';
4
4
  export const onResize = directive(class extends Directive {
5
5
  constructor(partInfo) {
@@ -9,7 +9,7 @@ export function createEventDescriptorMap(eventsInit) {
9
9
  return Object.keys(eventsInit)
10
10
  .filter((currentElementEventKey) => {
11
11
  if (typeof currentElementEventKey !== 'string') {
12
- throw new Error(`Expected event key of type string but got type "${typeof currentElementEventKey}" for key ${currentElementEventKey}`);
12
+ throw new Error(`Expected event key of type string but got type "${typeof currentElementEventKey}" for key ${String(currentElementEventKey)}`);
13
13
  }
14
14
  if (currentElementEventKey === '') {
15
15
  throw new Error(`Got empty string for events key.`);
@@ -1,5 +1,5 @@
1
- import { FunctionalElementInstanceFromInit } from './functional-element';
2
- export declare type PropertyInitMapBase = Record<string, unknown>;
1
+ import { DeclarativeElement } from './declarative-element';
2
+ export declare type PropertyInitMapBase = Record<PropertyKey, unknown>;
3
3
  export declare type ElementProperty<KeyGeneric extends string | number | symbol, ValueGeneric> = {
4
4
  name: KeyGeneric;
5
5
  setProp(value: ValueGeneric): void;
@@ -12,5 +12,5 @@ export declare type StaticElementPropertyDescriptor<PropName extends string, Pro
12
12
  export declare type ElementPropertyDescriptorMap<PropertyInitGeneric extends PropertyInitMapBase> = {
13
13
  [Property in keyof PropertyInitGeneric]: StaticElementPropertyDescriptor<string, PropertyInitGeneric[Property]>;
14
14
  };
15
- export declare function createPropertyProxy<PropertyInitGeneric extends PropertyInitMapBase>(propsInitMap: PropertyInitGeneric | undefined, element: FunctionalElementInstanceFromInit<PropertyInitGeneric>): PropertyInitGeneric;
15
+ export declare function createElementUpdaterProxy<PropertyInitGeneric extends PropertyInitMapBase>(element: DeclarativeElement, verifyExists: boolean): PropertyInitGeneric;
16
16
  export declare function createPropertyDescriptorMap<PropertyInitGeneric extends PropertyInitMapBase>(propertyInit: PropertyInitGeneric | undefined): ElementPropertyDescriptorMap<PropertyInitGeneric>;
@@ -0,0 +1,53 @@
1
+ function assertValidPropertyName(propKey, element, elementTagName) {
2
+ if (typeof propKey !== 'string' && typeof propKey !== 'number' && typeof propKey !== 'symbol') {
3
+ throw new Error(`Property name must be a string, got type "${typeof propKey}" from: "${String(propKey)}" for ${elementTagName.toLowerCase()}`);
4
+ }
5
+ if (!(propKey in element)) {
6
+ throw new Error(`Property "${String(propKey)}" does not exist on ${elementTagName.toLowerCase()}.`);
7
+ }
8
+ }
9
+ export function createElementUpdaterProxy(element, verifyExists) {
10
+ /**
11
+ * Lit element updates state and inputs by setting them directly on the element, so we must do
12
+ * that here. DeclarativeElement's types, however, do not expose this behavior, so we add that
13
+ * back in here.
14
+ */
15
+ const elementAsProps = element;
16
+ const propsProxy = new Proxy({}, {
17
+ get: (_target, propertyName) => {
18
+ if (verifyExists) {
19
+ assertValidPropertyName(propertyName, element, element.tagName);
20
+ }
21
+ return elementAsProps[propertyName];
22
+ },
23
+ set: (_target, propertyName, value) => {
24
+ if (verifyExists) {
25
+ assertValidPropertyName(propertyName, element, element.tagName);
26
+ }
27
+ elementAsProps[propertyName] = value;
28
+ return true;
29
+ },
30
+ });
31
+ return propsProxy;
32
+ }
33
+ export function createPropertyDescriptorMap(propertyInit) {
34
+ if (!propertyInit) {
35
+ return {};
36
+ }
37
+ return Object.keys(propertyInit)
38
+ .filter((key) => {
39
+ if (typeof key === 'string') {
40
+ return true;
41
+ }
42
+ else {
43
+ throw new Error(`Property init cannot have non string keys: "${key}"`);
44
+ }
45
+ })
46
+ .reduce((accum, currentKey) => {
47
+ accum[currentKey] = {
48
+ propName: currentKey,
49
+ initValue: propertyInit[currentKey],
50
+ };
51
+ return accum;
52
+ }, {});
53
+ }
@@ -0,0 +1 @@
1
+ export declare function hasDeclarativeElementParent(input: Element): boolean;
@@ -0,0 +1,16 @@
1
+ import { DeclarativeElement } from './declarative-element';
2
+ export function hasDeclarativeElementParent(input) {
3
+ const rootNode = input.getRootNode();
4
+ if (!(rootNode instanceof ShadowRoot)) {
5
+ // declarative elements all use shadow DOM, so if a shadow root doesn't exist then we're not
6
+ // in a declarative element.
7
+ return false;
8
+ }
9
+ const host = rootNode.host;
10
+ if (host instanceof DeclarativeElement) {
11
+ return true;
12
+ }
13
+ else {
14
+ return hasDeclarativeElementParent(host);
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ import { PropertyInitMapBase } from './element-properties';
2
+ import { WithTagName } from './tag-name';
3
+ export declare type HostClassToggleCallbackInput<InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase> = {
4
+ state: Readonly<StateGeneric>;
5
+ inputs: Readonly<InputsGeneric>;
6
+ };
7
+ export declare type HostClassToggleCallback<InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase> = (inputs: HostClassToggleCallbackInput<InputsGeneric, StateGeneric>) => boolean;
8
+ export declare type HostClassesInitMap<HostClassKeys extends string, InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase> = Record<HostClassKeys,
9
+ /**
10
+ * Callback to determine when host class should be enabled (based on current inputs and state),
11
+ * or just undefined to mark that this host class name will only be manually applied.
12
+ */
13
+ HostClassToggleCallback<InputsGeneric, StateGeneric> | false>;
14
+ export declare type HostClassName<TagName extends string, HostClassPropName extends string> = `${TagName}-${HostClassPropName}`;
15
+ export declare type HostClassNamesMap<TagName extends string, HostClassKeys extends string> = Record<HostClassKeys, WithTagName<TagName, string>>;
16
+ export declare function createHostClassNamesMap<TagName extends string, HostClassKeys extends string, HostClassesInitGeneric extends HostClassesInitMap<HostClassKeys,
17
+ /**
18
+ * We can use any here because we don't care what the state or input names are, we just care
19
+ * what the host class names are
20
+ */
21
+ any, any>>(tagName: TagName, hostClassesInit?: HostClassesInitGeneric): HostClassNamesMap<TagName, HostClassKeys>;
@@ -0,0 +1,22 @@
1
+ import { TemplateResult } from 'lit';
2
+ import { TypedEvent } from '../typed-event/typed-event';
3
+ import { DeclarativeElement } from './declarative-element';
4
+ import { EventDescriptorMap, EventInitMapEventDetailExtractor, EventsInitMap } from './element-events';
5
+ import { PropertyInitMapBase } from './element-properties';
6
+ export declare type RenderCallback<InputsGeneric extends PropertyInitMapBase = any, StateGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = any, CssVarKeys extends string = any> = (params: RenderParams<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) => TemplateResult;
7
+ export declare type InitCallback<InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = (params: RenderParams<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) => void;
8
+ export declare type UpdateStateCallback<StateGeneric extends PropertyInitMapBase> = (newState: Partial<StateGeneric>) => void;
9
+ export declare type RenderParams<InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = {
10
+ state: Readonly<StateGeneric>;
11
+ updateState: UpdateStateCallback<StateGeneric>;
12
+ events: EventDescriptorMap<EventsInitGeneric>;
13
+ host: DeclarativeElement<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
14
+ dispatch: <EventTypeNameGeneric extends keyof EventsInitGeneric>(event: TypedEvent<EventTypeNameGeneric extends string ? EventTypeNameGeneric : never, EventInitMapEventDetailExtractor<EventTypeNameGeneric, EventsInitGeneric>>) => boolean;
15
+ inputs: InputsGeneric;
16
+ /**
17
+ * Same as dispatchElementEvent but without the extra types. This allows you to emit any events,
18
+ * even events from other custom elements.
19
+ */
20
+ genericDispatch: (event: Event) => boolean;
21
+ };
22
+ export declare function createRenderParams<InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string>(element: DeclarativeElement<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>, eventsMap: EventDescriptorMap<EventsInitGeneric>): RenderParams<InputsGeneric, StateGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
@@ -7,13 +7,14 @@ export function createRenderParams(element, eventsMap) {
7
7
  */
8
8
  dispatch: (event) => element.dispatchEvent(event),
9
9
  genericDispatch: (event) => element.dispatchEvent(event),
10
- setProps: (partialProps) => {
10
+ updateState: (partialProps) => {
11
11
  getObjectTypedKeys(partialProps).forEach((propKey) => {
12
- element.instanceProps[propKey] = partialProps[propKey];
12
+ element.instanceState[propKey] = partialProps[propKey];
13
13
  });
14
14
  },
15
+ inputs: element.instanceInputs,
15
16
  host: element,
16
- props: element.instanceProps,
17
+ state: element.instanceState,
17
18
  events: eventsMap,
18
19
  };
19
20
  return renderParams;
@@ -13,4 +13,10 @@ export declare function hostClassNamesToStylesInput<HostClassKeys extends string
13
13
  cssVarNames: CssVarNameOrValueMap<CssVarKeys>;
14
14
  cssVarValues: CssVarNameOrValueMap<CssVarKeys>;
15
15
  }): StylesCallbackInput<HostClassKeys, CssVarKeys>;
16
- export declare function applyHostClasses<PropertyInitGeneric extends PropertyInitMapBase, HostClassKeys extends string>(host: HTMLElement, hostClassesInit: Readonly<HostClassesInitMap<HostClassKeys, PropertyInitGeneric>> | undefined, hostClassNames: HostClassNamesMap<string, HostClassKeys>, props: Readonly<PropertyInitGeneric>): void;
16
+ export declare function applyHostClasses<InputsGeneric extends PropertyInitMapBase, StateGeneric extends PropertyInitMapBase, HostClassKeys extends string>({ host, hostClassesInit, hostClassNames, state, inputs, }: {
17
+ host: HTMLElement;
18
+ hostClassesInit: Readonly<HostClassesInitMap<HostClassKeys, InputsGeneric, StateGeneric>> | undefined;
19
+ hostClassNames: HostClassNamesMap<string, HostClassKeys>;
20
+ state: Readonly<StateGeneric>;
21
+ inputs: Readonly<InputsGeneric>;
22
+ }): void;
@@ -9,7 +9,7 @@ export function hostClassNamesToStylesInput({ hostClassNames, cssVarNames, cssVa
9
9
  cssVarValue: cssVarValues,
10
10
  };
11
11
  }
12
- export function applyHostClasses(host, hostClassesInit, hostClassNames, props) {
12
+ export function applyHostClasses({ host, hostClassesInit, hostClassNames, state, inputs, }) {
13
13
  if (!hostClassesInit) {
14
14
  return;
15
15
  }
@@ -17,7 +17,7 @@ export function applyHostClasses(host, hostClassesInit, hostClassNames, props) {
17
17
  const maybeCallback = hostClassesInit[hostClassKey];
18
18
  const hostClassName = hostClassNames[hostClassKey];
19
19
  if (typeof maybeCallback === 'function') {
20
- const shouldApplyHostClass = maybeCallback({ props });
20
+ const shouldApplyHostClass = maybeCallback({ state, inputs });
21
21
  if (shouldApplyHostClass) {
22
22
  host.classList.add(hostClassName);
23
23
  }
@@ -0,0 +1 @@
1
+ export declare const DeclarativeElementMarkerSymbol: unique symbol;
@@ -0,0 +1 @@
1
+ export const DeclarativeElementMarkerSymbol = Symbol('this-is-an-element-vir-declarative-element');
package/dist/index.d.ts CHANGED
@@ -1,15 +1,17 @@
1
- export * from './functional-element/define-functional-element';
2
- export * from './functional-element/directives/assign-with-clean-up.directive';
3
- export * from './functional-element/directives/assign.directive';
4
- export * from './functional-element/directives/directive-util';
5
- export * from './functional-element/directives/listen.directive';
6
- export * from './functional-element/directives/on-dom-created.directive';
7
- export * from './functional-element/directives/on-resize.directive';
8
- export * from './functional-element/element-events';
9
- export * from './functional-element/element-properties';
10
- export * from './functional-element/functional-element';
11
- export * from './functional-element/render-callback';
12
- export { requireAllCustomElementsToBeFunctionalElement } from './require-functional-element';
1
+ export * from './declarative-element/declarative-element';
2
+ export * from './declarative-element/define-element';
3
+ export * from './declarative-element/define-element-no-inputs';
4
+ export type { DeclarativeElementDefinitionOptions } from './declarative-element/definition-options';
5
+ export * from './declarative-element/directives/assign-with-clean-up.directive';
6
+ export * from './declarative-element/directives/assign.directive';
7
+ export * from './declarative-element/directives/directive-helpers';
8
+ export * from './declarative-element/directives/listen.directive';
9
+ export * from './declarative-element/directives/on-dom-created.directive';
10
+ export * from './declarative-element/directives/on-resize.directive';
11
+ export * from './declarative-element/element-events';
12
+ export * from './declarative-element/element-properties';
13
+ export * from './declarative-element/render-callback';
14
+ export { requireAllCustomElementsToBeDeclarativeElements } from './require-declarative-element';
13
15
  export * from './template-transforms/vir-css/vir-css';
14
16
  export * from './template-transforms/vir-html/vir-html';
15
17
  export * from './typed-event/typed-event';