element-vir 26.11.2 → 26.12.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/package.json +12 -12
- package/src/declarative-element/declarative-element-init.ts +115 -0
- package/src/declarative-element/declarative-element.ts +372 -0
- package/src/declarative-element/define-element.ts +515 -0
- package/{dist/declarative-element/definition-options.d.ts → src/declarative-element/definition-options.ts} +7 -2
- package/src/declarative-element/directives/assign.directive.ts +89 -0
- package/{dist/declarative-element/directives/async-prop.js → src/declarative-element/directives/async-prop.ts} +42 -8
- package/src/declarative-element/directives/attributes.directive.ts +63 -0
- package/src/declarative-element/directives/create-attribute-directive.ts +47 -0
- package/src/declarative-element/directives/directive-helpers.ts +67 -0
- package/{dist/declarative-element/directives/listen-to-activate.js → src/declarative-element/directives/listen-to-activate.ts} +8 -3
- package/src/declarative-element/directives/listen.directive.ts +206 -0
- package/src/declarative-element/directives/mutate.directive.ts +78 -0
- package/src/declarative-element/directives/on-dom-created.directive.ts +68 -0
- package/src/declarative-element/directives/on-dom-rendered.directive.ts +61 -0
- package/src/declarative-element/directives/on-intersect.directive.ts +139 -0
- package/src/declarative-element/directives/on-resize.directive.ts +142 -0
- package/src/declarative-element/directives/render-async.directive.ts +111 -0
- package/{dist/declarative-element/directives/render-if.directive.js → src/declarative-element/directives/render-if.directive.ts} +12 -3
- package/{dist/declarative-element/directives/test-id.directive.js → src/declarative-element/directives/test-id.directive.ts} +7 -2
- package/{dist/declarative-element/has-declarative-element-parent.js → src/declarative-element/has-declarative-element-parent.ts} +7 -4
- package/{dist/declarative-element/is-declarative-element-definition.js → src/declarative-element/is-declarative-element-definition.ts} +28 -11
- package/{dist/declarative-element/is-declarative-element.js → src/declarative-element/is-declarative-element.ts} +11 -5
- package/src/declarative-element/properties/assign-inputs.ts +30 -0
- package/src/declarative-element/properties/css-vars.ts +24 -0
- package/src/declarative-element/properties/element-events.ts +161 -0
- package/src/declarative-element/properties/host-classes.ts +63 -0
- package/{dist/declarative-element/properties/property-proxy.js → src/declarative-element/properties/property-proxy.ts} +58 -21
- package/src/declarative-element/properties/string-names.ts +83 -0
- package/src/declarative-element/properties/styles.ts +112 -0
- package/src/declarative-element/render-callback.ts +196 -0
- package/src/declarative-element/wrap-define-element.ts +127 -0
- package/{dist/index.d.ts → src/index.ts} +2 -0
- package/{dist/lit-exports/base-lit-exports.js → src/lit-exports/base-lit-exports.ts} +10 -1
- package/{dist/lit-exports/lit-repeat-fix.d.ts → src/lit-exports/lit-repeat-fix.ts} +45 -16
- package/{dist/readme-examples/my-app.element.js → src/readme-examples/my-app.element.ts} +5 -4
- package/src/readme-examples/my-custom-action.event.ts +3 -0
- package/{dist/readme-examples/my-custom-define.js → src/readme-examples/my-custom-define.ts} +9 -4
- package/{dist/readme-examples/my-simple.element.js → src/readme-examples/my-simple.element.ts} +4 -3
- package/src/readme-examples/my-with-assignment.element.ts +16 -0
- package/{dist/readme-examples/my-with-async-prop.element.js → src/readme-examples/my-with-async-prop.element.ts} +24 -16
- package/{dist/readme-examples/my-with-cleanup-callback.element.js → src/readme-examples/my-with-cleanup-callback.element.ts} +5 -4
- package/{dist/readme-examples/my-with-css-vars.element.js → src/readme-examples/my-with-css-vars.element.ts} +5 -4
- package/src/readme-examples/my-with-custom-events.element.ts +23 -0
- package/{dist/readme-examples/my-with-event-listening.element.js → src/readme-examples/my-with-event-listening.element.ts} +10 -9
- package/src/readme-examples/my-with-events.element.ts +23 -0
- package/{dist/readme-examples/my-with-host-class-definition.element.js → src/readme-examples/my-with-host-class-definition.element.ts} +7 -6
- package/{dist/readme-examples/my-with-host-class-usage.element.js → src/readme-examples/my-with-host-class-usage.element.ts} +5 -4
- package/src/readme-examples/my-with-inputs.element.ts +13 -0
- package/{dist/readme-examples/my-with-on-dom-created.element.js → src/readme-examples/my-with-on-dom-created.element.ts} +7 -6
- package/src/readme-examples/my-with-on-resize.element.ts +19 -0
- package/src/readme-examples/my-with-render-if.element.ts +15 -0
- package/{dist/readme-examples/my-with-styles-and-interpolated-selector.element.js → src/readme-examples/my-with-styles-and-interpolated-selector.element.ts} +6 -5
- package/{dist/readme-examples/my-with-styles.element.js → src/readme-examples/my-with-styles.element.ts} +5 -4
- package/{dist/readme-examples/my-with-update-state.element.js → src/readme-examples/my-with-update-state.element.ts} +8 -7
- package/src/readme-examples/require-declarative-element.ts +3 -0
- package/{dist/require-declarative-element.js → src/require-declarative-element.ts} +1 -0
- package/{dist/template-transforms/minimal-element-definition.d.ts → src/template-transforms/minimal-element-definition.ts} +19 -7
- package/src/template-transforms/nested-mapped-templates.ts +157 -0
- package/{dist/template-transforms/template-transform-type.d.ts → src/template-transforms/template-transform-type.ts} +3 -1
- package/{dist/template-transforms/transform-template.js → src/template-transforms/transform-template.ts} +70 -22
- package/src/template-transforms/vir-css/css-transform.ts +30 -0
- package/src/template-transforms/vir-css/vir-css.ts +30 -0
- package/src/template-transforms/vir-html/html-interpolation.ts +103 -0
- package/src/template-transforms/vir-html/html-transform.ts +149 -0
- package/{dist/template-transforms/vir-html/tag-name-keys.js → src/template-transforms/vir-html/tag-name-keys.ts} +1 -1
- package/{dist/template-transforms/vir-html/vir-html.js → src/template-transforms/vir-html/vir-html.ts} +13 -5
- package/src/typed-event/typed-event.ts +90 -0
- package/{dist/util/array.js → src/util/array.ts} +18 -5
- package/{dist/util/increment.d.ts → src/util/increment.ts} +24 -5
- package/{dist/util/lit-template.js → src/util/lit-template.ts} +30 -10
- package/src/util/map-async-value.ts +33 -0
- package/dist/declarative-element/custom-tag-name.js +0 -1
- package/dist/declarative-element/declarative-element-init.d.ts +0 -56
- package/dist/declarative-element/declarative-element-init.js +0 -1
- package/dist/declarative-element/declarative-element.d.ts +0 -114
- package/dist/declarative-element/declarative-element.js +0 -36
- package/dist/declarative-element/define-element.d.ts +0 -41
- package/dist/declarative-element/define-element.js +0 -248
- package/dist/declarative-element/definition-options.js +0 -9
- package/dist/declarative-element/directives/assign.directive.d.ts +0 -24
- package/dist/declarative-element/directives/assign.directive.js +0 -34
- package/dist/declarative-element/directives/async-prop.d.ts +0 -61
- package/dist/declarative-element/directives/attributes.directive.d.ts +0 -30
- package/dist/declarative-element/directives/attributes.directive.js +0 -35
- package/dist/declarative-element/directives/create-attribute-directive.d.ts +0 -28
- package/dist/declarative-element/directives/create-attribute-directive.js +0 -41
- package/dist/declarative-element/directives/directive-helpers.d.ts +0 -27
- package/dist/declarative-element/directives/directive-helpers.js +0 -37
- package/dist/declarative-element/directives/listen-to-activate.d.ts +0 -15
- package/dist/declarative-element/directives/listen.directive.d.ts +0 -92
- package/dist/declarative-element/directives/listen.directive.js +0 -48
- package/dist/declarative-element/directives/mutate.directive.d.ts +0 -38
- package/dist/declarative-element/directives/mutate.directive.js +0 -45
- package/dist/declarative-element/directives/on-dom-created.directive.d.ts +0 -44
- package/dist/declarative-element/directives/on-dom-created.directive.js +0 -51
- package/dist/declarative-element/directives/on-dom-rendered.directive.d.ts +0 -41
- package/dist/declarative-element/directives/on-dom-rendered.directive.js +0 -45
- package/dist/declarative-element/directives/on-intersect.directive.d.ts +0 -64
- package/dist/declarative-element/directives/on-intersect.directive.js +0 -89
- package/dist/declarative-element/directives/on-resize.directive.d.ts +0 -74
- package/dist/declarative-element/directives/on-resize.directive.js +0 -106
- package/dist/declarative-element/directives/render-async.directive.d.ts +0 -45
- package/dist/declarative-element/directives/render-async.directive.js +0 -33
- package/dist/declarative-element/directives/render-if.directive.d.ts +0 -32
- package/dist/declarative-element/directives/test-id.directive.d.ts +0 -52
- package/dist/declarative-element/has-declarative-element-parent.d.ts +0 -1
- package/dist/declarative-element/is-declarative-element-definition.d.ts +0 -17
- package/dist/declarative-element/is-declarative-element.d.ts +0 -15
- package/dist/declarative-element/properties/assign-inputs.d.ts +0 -1
- package/dist/declarative-element/properties/assign-inputs.js +0 -25
- package/dist/declarative-element/properties/css-vars.d.ts +0 -16
- package/dist/declarative-element/properties/css-vars.js +0 -1
- package/dist/declarative-element/properties/element-events.d.ts +0 -65
- package/dist/declarative-element/properties/element-events.js +0 -62
- package/dist/declarative-element/properties/element-properties.js +0 -1
- package/dist/declarative-element/properties/host-classes.d.ts +0 -36
- package/dist/declarative-element/properties/host-classes.js +0 -16
- package/dist/declarative-element/properties/property-proxy.d.ts +0 -22
- package/dist/declarative-element/properties/string-names.d.ts +0 -28
- package/dist/declarative-element/properties/string-names.js +0 -40
- package/dist/declarative-element/properties/styles.d.ts +0 -51
- package/dist/declarative-element/properties/styles.js +0 -41
- package/dist/declarative-element/properties/tag-name.js +0 -1
- package/dist/declarative-element/render-callback.d.ts +0 -56
- package/dist/declarative-element/render-callback.js +0 -27
- package/dist/declarative-element/wrap-define-element.d.ts +0 -36
- package/dist/declarative-element/wrap-define-element.js +0 -25
- package/dist/index.js +0 -42
- package/dist/lit-exports/all-lit-exports.js +0 -2
- package/dist/lit-exports/base-lit-exports.d.ts +0 -25
- package/dist/lit-exports/lit-repeat-fix.js +0 -37
- package/dist/readme-examples/my-app.element.d.ts +0 -1
- package/dist/readme-examples/my-custom-action.event.d.ts +0 -1
- package/dist/readme-examples/my-custom-action.event.js +0 -2
- package/dist/readme-examples/my-custom-define.d.ts +0 -4
- package/dist/readme-examples/my-simple.element.d.ts +0 -1
- package/dist/readme-examples/my-with-assignment.element.d.ts +0 -1
- package/dist/readme-examples/my-with-assignment.element.js +0 -15
- package/dist/readme-examples/my-with-async-prop.element.d.ts +0 -10
- package/dist/readme-examples/my-with-cleanup-callback.element.d.ts +0 -3
- package/dist/readme-examples/my-with-css-vars.element.d.ts +0 -1
- package/dist/readme-examples/my-with-custom-events.element.d.ts +0 -1
- package/dist/readme-examples/my-with-custom-events.element.js +0 -22
- package/dist/readme-examples/my-with-event-listening.element.d.ts +0 -3
- package/dist/readme-examples/my-with-events.element.d.ts +0 -4
- package/dist/readme-examples/my-with-events.element.js +0 -20
- package/dist/readme-examples/my-with-host-class-definition.element.d.ts +0 -3
- package/dist/readme-examples/my-with-host-class-usage.element.d.ts +0 -1
- package/dist/readme-examples/my-with-inputs.element.d.ts +0 -4
- package/dist/readme-examples/my-with-inputs.element.js +0 -9
- package/dist/readme-examples/my-with-on-dom-created.element.d.ts +0 -1
- package/dist/readme-examples/my-with-on-resize.element.d.ts +0 -1
- package/dist/readme-examples/my-with-on-resize.element.js +0 -18
- package/dist/readme-examples/my-with-render-if.element.d.ts +0 -3
- package/dist/readme-examples/my-with-render-if.element.js +0 -11
- package/dist/readme-examples/my-with-styles-and-interpolated-selector.element.d.ts +0 -1
- package/dist/readme-examples/my-with-styles.element.d.ts +0 -1
- package/dist/readme-examples/my-with-update-state.element.d.ts +0 -8
- package/dist/readme-examples/require-declarative-element.d.ts +0 -1
- package/dist/readme-examples/require-declarative-element.js +0 -2
- package/dist/require-declarative-element.d.ts +0 -14
- package/dist/template-transforms/minimal-element-definition.js +0 -19
- package/dist/template-transforms/nested-mapped-templates.d.ts +0 -6
- package/dist/template-transforms/nested-mapped-templates.js +0 -96
- package/dist/template-transforms/template-transform-type.js +0 -1
- package/dist/template-transforms/transform-template.d.ts +0 -14
- package/dist/template-transforms/vir-css/css-transform.d.ts +0 -4
- package/dist/template-transforms/vir-css/css-transform.js +0 -15
- package/dist/template-transforms/vir-css/vir-css.d.ts +0 -12
- package/dist/template-transforms/vir-css/vir-css.js +0 -21
- package/dist/template-transforms/vir-html/html-interpolation.d.ts +0 -42
- package/dist/template-transforms/vir-html/html-interpolation.js +0 -1
- package/dist/template-transforms/vir-html/html-transform.d.ts +0 -5
- package/dist/template-transforms/vir-html/html-transform.js +0 -96
- package/dist/template-transforms/vir-html/tag-name-keys.d.ts +0 -7
- package/dist/template-transforms/vir-html/vir-html.d.ts +0 -11
- package/dist/typed-event/typed-event.d.ts +0 -55
- package/dist/typed-event/typed-event.js +0 -50
- package/dist/util/array.d.ts +0 -5
- package/dist/util/increment.js +0 -1
- package/dist/util/lit-template.d.ts +0 -9
- package/dist/util/type.js +0 -1
- /package/{dist/declarative-element/custom-tag-name.d.ts → src/declarative-element/custom-tag-name.ts} +0 -0
- /package/{dist/declarative-element/properties/element-properties.d.ts → src/declarative-element/properties/element-properties.ts} +0 -0
- /package/{dist/declarative-element/properties/tag-name.d.ts → src/declarative-element/properties/tag-name.ts} +0 -0
- /package/{dist/lit-exports/all-lit-exports.d.ts → src/lit-exports/all-lit-exports.ts} +0 -0
- /package/{dist/util/type.d.ts → src/util/type.ts} +0 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
|
2
|
+
|
|
3
|
+
import {assert, check} from '@augment-vir/assert';
|
|
4
|
+
import {
|
|
5
|
+
StringCase,
|
|
6
|
+
ensureErrorAndPrependMessage,
|
|
7
|
+
extractErrorMessage,
|
|
8
|
+
getObjectTypedKeys,
|
|
9
|
+
kebabCaseToCamelCase,
|
|
10
|
+
} from '@augment-vir/common';
|
|
11
|
+
import {defineCssVars} from 'lit-css-vars';
|
|
12
|
+
import {type MinimalDefinitionWithInputs} from '../template-transforms/minimal-element-definition.js';
|
|
13
|
+
import {css} from '../template-transforms/vir-css/vir-css.js';
|
|
14
|
+
import {type CustomElementTagName} from './custom-tag-name.js';
|
|
15
|
+
import {type DeclarativeElementInit} from './declarative-element-init.js';
|
|
16
|
+
import {
|
|
17
|
+
DeclarativeElement,
|
|
18
|
+
type DeclarativeElementDefinition,
|
|
19
|
+
type StaticDeclarativeElementProperties,
|
|
20
|
+
} from './declarative-element.js';
|
|
21
|
+
import {
|
|
22
|
+
type DeclarativeElementDefinitionOptions,
|
|
23
|
+
defaultDeclarativeElementDefinitionOptions,
|
|
24
|
+
} from './definition-options.js';
|
|
25
|
+
import {assignInputs} from './properties/assign-inputs.js';
|
|
26
|
+
import {type CssVars} from './properties/css-vars.js';
|
|
27
|
+
import {
|
|
28
|
+
type EventDescriptorMap,
|
|
29
|
+
type EventsInitMap,
|
|
30
|
+
createEventDescriptorMap,
|
|
31
|
+
} from './properties/element-events.js';
|
|
32
|
+
import {type PropertyInitMapBase} from './properties/element-properties.js';
|
|
33
|
+
import {type HostClassNamesMap, createHostClassNamesMap} from './properties/host-classes.js';
|
|
34
|
+
import {bindReactiveProperty, createElementPropertyProxy} from './properties/property-proxy.js';
|
|
35
|
+
import {
|
|
36
|
+
type BaseStringName,
|
|
37
|
+
assertValidStringNames,
|
|
38
|
+
createStringNameMap,
|
|
39
|
+
} from './properties/string-names.js';
|
|
40
|
+
import {applyHostClasses, createStylesCallbackInput} from './properties/styles.js';
|
|
41
|
+
import {type RenderParams, createRenderParams} from './render-callback.js';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Verifies that the given `Inputs` type does not clash with built-in HTMLElement properties. This
|
|
45
|
+
* is used within {@link defineElement}.
|
|
46
|
+
*
|
|
47
|
+
* @category Internal
|
|
48
|
+
*/
|
|
49
|
+
export type DeclarativeElementInputErrorParams<Inputs extends PropertyInitMapBase> =
|
|
50
|
+
Extract<keyof Inputs, keyof HTMLElement> extends never
|
|
51
|
+
? []
|
|
52
|
+
: [
|
|
53
|
+
'ERROR: Cannot define an element input property that clashes with native HTMLElement properties.',
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Defines an element with inputs. Note that this function must be called twice, due to TypeScript
|
|
58
|
+
* type inference limitations.
|
|
59
|
+
*
|
|
60
|
+
* @category Element Definition
|
|
61
|
+
* @example
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* import {defineElement, html} from 'element-vir';
|
|
65
|
+
*
|
|
66
|
+
* const MyElement = defineElement<{username: string}>()({
|
|
67
|
+
* tagName: 'my-element',
|
|
68
|
+
* render({inputs}) {
|
|
69
|
+
* return html`
|
|
70
|
+
* <p>hi: ${inputs.username}</p>
|
|
71
|
+
* `;
|
|
72
|
+
* },
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function defineElement<Inputs extends PropertyInitMapBase = {}>(
|
|
77
|
+
/**
|
|
78
|
+
* These `errorParams` is present when there are problems with the `Inputs` type. If it is
|
|
79
|
+
* present, the error should be fixed. This should always be empty.
|
|
80
|
+
*/
|
|
81
|
+
...errorParams: DeclarativeElementInputErrorParams<Inputs>
|
|
82
|
+
) {
|
|
83
|
+
assert.isEmpty(errorParams);
|
|
84
|
+
|
|
85
|
+
return <
|
|
86
|
+
const TagName extends CustomElementTagName,
|
|
87
|
+
State extends PropertyInitMapBase = {},
|
|
88
|
+
EventsInit extends EventsInitMap = {},
|
|
89
|
+
const HostClassKeys extends BaseStringName<TagName> = `${TagName}-`,
|
|
90
|
+
const CssVarKeys extends BaseStringName<TagName> = `${TagName}-`,
|
|
91
|
+
const SlotNames extends ReadonlyArray<string> = Readonly<[]>,
|
|
92
|
+
const TestIds extends ReadonlyArray<string> = Readonly<[]>,
|
|
93
|
+
>(
|
|
94
|
+
initInput: DeclarativeElementInit<
|
|
95
|
+
TagName,
|
|
96
|
+
Inputs,
|
|
97
|
+
State,
|
|
98
|
+
EventsInit,
|
|
99
|
+
HostClassKeys,
|
|
100
|
+
CssVarKeys,
|
|
101
|
+
SlotNames,
|
|
102
|
+
TestIds
|
|
103
|
+
>,
|
|
104
|
+
): DeclarativeElementDefinition<
|
|
105
|
+
TagName,
|
|
106
|
+
Inputs,
|
|
107
|
+
State,
|
|
108
|
+
EventsInit,
|
|
109
|
+
HostClassKeys,
|
|
110
|
+
CssVarKeys,
|
|
111
|
+
SlotNames,
|
|
112
|
+
TestIds
|
|
113
|
+
> => {
|
|
114
|
+
const init:
|
|
115
|
+
| string
|
|
116
|
+
| DeclarativeElementInit<
|
|
117
|
+
TagName,
|
|
118
|
+
Inputs,
|
|
119
|
+
State,
|
|
120
|
+
EventsInit,
|
|
121
|
+
HostClassKeys,
|
|
122
|
+
CssVarKeys,
|
|
123
|
+
SlotNames,
|
|
124
|
+
TestIds
|
|
125
|
+
> = initInput;
|
|
126
|
+
|
|
127
|
+
if (!check.isObject(init)) {
|
|
128
|
+
throw new TypeError('Cannot define element with non-object init: ${init}');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return internalDefineElement({
|
|
132
|
+
...init,
|
|
133
|
+
options: {
|
|
134
|
+
...init.options,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function internalDefineElement<
|
|
141
|
+
const TagName extends CustomElementTagName = '-',
|
|
142
|
+
Inputs extends PropertyInitMapBase = {},
|
|
143
|
+
State extends PropertyInitMapBase = {},
|
|
144
|
+
EventsInit extends EventsInitMap = {},
|
|
145
|
+
const HostClassKeys extends BaseStringName<TagName> = `${TagName}-`,
|
|
146
|
+
const CssVarKeys extends BaseStringName<TagName> = `${TagName}-`,
|
|
147
|
+
const SlotNames extends ReadonlyArray<string> = Readonly<[]>,
|
|
148
|
+
const TestIds extends ReadonlyArray<string> = Readonly<[]>,
|
|
149
|
+
>(
|
|
150
|
+
init: DeclarativeElementInit<
|
|
151
|
+
TagName,
|
|
152
|
+
Inputs,
|
|
153
|
+
State,
|
|
154
|
+
EventsInit,
|
|
155
|
+
HostClassKeys,
|
|
156
|
+
CssVarKeys,
|
|
157
|
+
SlotNames,
|
|
158
|
+
TestIds
|
|
159
|
+
>,
|
|
160
|
+
): DeclarativeElementDefinition<
|
|
161
|
+
TagName,
|
|
162
|
+
Inputs,
|
|
163
|
+
State,
|
|
164
|
+
EventsInit,
|
|
165
|
+
HostClassKeys,
|
|
166
|
+
CssVarKeys,
|
|
167
|
+
SlotNames,
|
|
168
|
+
TestIds
|
|
169
|
+
> {
|
|
170
|
+
if (!check.isObject(init)) {
|
|
171
|
+
throw new TypeError('Cannot define element with non-object init: ${init}');
|
|
172
|
+
}
|
|
173
|
+
if (!check.isString(init.tagName)) {
|
|
174
|
+
throw new TypeError('Missing valid tagName (expected a string).');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
type ThisElementDefinition = DeclarativeElementDefinition<
|
|
178
|
+
TagName,
|
|
179
|
+
Inputs,
|
|
180
|
+
State,
|
|
181
|
+
EventsInit,
|
|
182
|
+
HostClassKeys,
|
|
183
|
+
CssVarKeys,
|
|
184
|
+
SlotNames,
|
|
185
|
+
TestIds
|
|
186
|
+
>;
|
|
187
|
+
type ThisElementStaticClass = typeof DeclarativeElement<
|
|
188
|
+
TagName,
|
|
189
|
+
Inputs,
|
|
190
|
+
State,
|
|
191
|
+
EventsInit,
|
|
192
|
+
HostClassKeys,
|
|
193
|
+
CssVarKeys,
|
|
194
|
+
SlotNames,
|
|
195
|
+
TestIds
|
|
196
|
+
>;
|
|
197
|
+
type ThisElementInstance = InstanceType<ThisElementStaticClass>;
|
|
198
|
+
|
|
199
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
200
|
+
if (!init.render || typeof init.render === 'string') {
|
|
201
|
+
throw new Error(`Failed to define element '${init.tagName}': render is not a function`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const elementOptions: DeclarativeElementDefinitionOptions = {
|
|
205
|
+
...defaultDeclarativeElementDefinitionOptions,
|
|
206
|
+
...init.options,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const eventsMap: EventDescriptorMap<TagName, EventsInit> = createEventDescriptorMap(
|
|
210
|
+
init.tagName,
|
|
211
|
+
init.events,
|
|
212
|
+
);
|
|
213
|
+
const hostClassNames: HostClassNamesMap<TagName, HostClassKeys> = createHostClassNamesMap(
|
|
214
|
+
init.hostClasses,
|
|
215
|
+
);
|
|
216
|
+
if (init.hostClasses) {
|
|
217
|
+
assertValidStringNames(init.tagName, init.hostClasses);
|
|
218
|
+
}
|
|
219
|
+
if (init.cssVars) {
|
|
220
|
+
assertValidStringNames(init.tagName, init.cssVars);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* As casts here are to prevent defineCssVars from complaining that our CSS var names are too
|
|
224
|
+
* generic or the names not being in kebab-case. (Which, in this line of code, are indeed true
|
|
225
|
+
* errors. However, this is for internal types only and the user will actually see much more
|
|
226
|
+
* specific types externally.)
|
|
227
|
+
*/
|
|
228
|
+
const cssVars = (init.cssVars ? defineCssVars(init.cssVars as any) : {}) as CssVars<
|
|
229
|
+
TagName,
|
|
230
|
+
CssVarKeys
|
|
231
|
+
>;
|
|
232
|
+
|
|
233
|
+
const slotNamesMap: StaticDeclarativeElementProperties<
|
|
234
|
+
TagName,
|
|
235
|
+
Inputs,
|
|
236
|
+
State,
|
|
237
|
+
EventsInit,
|
|
238
|
+
HostClassKeys,
|
|
239
|
+
CssVarKeys,
|
|
240
|
+
SlotNames,
|
|
241
|
+
TestIds
|
|
242
|
+
>['slotNames'] = createStringNameMap(init.tagName, 'slot', init.slotNames);
|
|
243
|
+
const testIdsMap: StaticDeclarativeElementProperties<
|
|
244
|
+
TagName,
|
|
245
|
+
Inputs,
|
|
246
|
+
State,
|
|
247
|
+
EventsInit,
|
|
248
|
+
HostClassKeys,
|
|
249
|
+
CssVarKeys,
|
|
250
|
+
SlotNames,
|
|
251
|
+
TestIds
|
|
252
|
+
>['testIds'] = createStringNameMap(init.tagName, 'test-id', init.testIds);
|
|
253
|
+
|
|
254
|
+
const calculatedStyles =
|
|
255
|
+
typeof init.styles === 'function'
|
|
256
|
+
? init.styles(createStylesCallbackInput({hostClassNames, cssVars}))
|
|
257
|
+
: init.styles || css``;
|
|
258
|
+
|
|
259
|
+
const typedRenderCallback: StaticDeclarativeElementProperties<
|
|
260
|
+
TagName,
|
|
261
|
+
Inputs,
|
|
262
|
+
State,
|
|
263
|
+
EventsInit,
|
|
264
|
+
HostClassKeys,
|
|
265
|
+
CssVarKeys,
|
|
266
|
+
SlotNames,
|
|
267
|
+
TestIds
|
|
268
|
+
>['render'] = init.render;
|
|
269
|
+
|
|
270
|
+
function typedAssignCallback(...[inputs]: Parameters<ThisElementStaticClass['assign']>) {
|
|
271
|
+
const wrappedDefinition: MinimalDefinitionWithInputs = {
|
|
272
|
+
_elementVirIsMinimalDefinitionWithInputs: true,
|
|
273
|
+
definition: anonymousClass,
|
|
274
|
+
inputs,
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
return wrappedDefinition;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const anonymousClass = class extends DeclarativeElement<
|
|
281
|
+
TagName,
|
|
282
|
+
Inputs,
|
|
283
|
+
State,
|
|
284
|
+
EventsInit,
|
|
285
|
+
HostClassKeys,
|
|
286
|
+
CssVarKeys,
|
|
287
|
+
SlotNames,
|
|
288
|
+
TestIds
|
|
289
|
+
> {
|
|
290
|
+
public static override readonly elementOptions = elementOptions;
|
|
291
|
+
public static override readonly tagName = init.tagName;
|
|
292
|
+
public static override readonly styles = calculatedStyles;
|
|
293
|
+
|
|
294
|
+
public _lastRenderError: Error | undefined = undefined;
|
|
295
|
+
public _internalRenderCount = 0;
|
|
296
|
+
|
|
297
|
+
public createRenderParams(): RenderParams<
|
|
298
|
+
TagName,
|
|
299
|
+
Inputs,
|
|
300
|
+
State,
|
|
301
|
+
EventsInit,
|
|
302
|
+
HostClassKeys,
|
|
303
|
+
CssVarKeys,
|
|
304
|
+
SlotNames,
|
|
305
|
+
TestIds
|
|
306
|
+
> {
|
|
307
|
+
return createRenderParams({
|
|
308
|
+
element: this,
|
|
309
|
+
eventsMap,
|
|
310
|
+
cssVars,
|
|
311
|
+
slotNamesMap,
|
|
312
|
+
testIdsMap,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
public static override readonly assign = typedAssignCallback as any;
|
|
317
|
+
|
|
318
|
+
public static override readonly events: StaticDeclarativeElementProperties<
|
|
319
|
+
TagName,
|
|
320
|
+
Inputs,
|
|
321
|
+
State,
|
|
322
|
+
EventsInit,
|
|
323
|
+
HostClassKeys,
|
|
324
|
+
CssVarKeys,
|
|
325
|
+
SlotNames,
|
|
326
|
+
TestIds
|
|
327
|
+
>['events'] = eventsMap;
|
|
328
|
+
public static override readonly render: ThisElementStaticClass['render'] =
|
|
329
|
+
typedRenderCallback as any as ThisElementStaticClass['render'];
|
|
330
|
+
public static override readonly hostClasses: StaticDeclarativeElementProperties<
|
|
331
|
+
TagName,
|
|
332
|
+
Inputs,
|
|
333
|
+
State,
|
|
334
|
+
EventsInit,
|
|
335
|
+
HostClassKeys,
|
|
336
|
+
CssVarKeys,
|
|
337
|
+
SlotNames,
|
|
338
|
+
TestIds
|
|
339
|
+
>['hostClasses'] = hostClassNames;
|
|
340
|
+
public static override readonly cssVars: StaticDeclarativeElementProperties<
|
|
341
|
+
TagName,
|
|
342
|
+
Inputs,
|
|
343
|
+
State,
|
|
344
|
+
EventsInit,
|
|
345
|
+
HostClassKeys,
|
|
346
|
+
CssVarKeys,
|
|
347
|
+
SlotNames,
|
|
348
|
+
TestIds
|
|
349
|
+
>['cssVars'] = cssVars;
|
|
350
|
+
public static override readonly init = init as any;
|
|
351
|
+
public static override readonly slotNames = slotNamesMap as any;
|
|
352
|
+
public static override readonly testIds = testIdsMap as any;
|
|
353
|
+
public get InstanceType() {
|
|
354
|
+
throw new Error(
|
|
355
|
+
`'InstanceType' was called on ${init.tagName} as a value but it is only a type.`,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
public static override get InputsType(): Inputs {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`'InputsType' was called on ${init.tagName} as a value but it is only a type.`,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
public static override get StateType(): State {
|
|
364
|
+
throw new Error(
|
|
365
|
+
`'StateType' was called on ${init.tagName} as a value but it is only a type.`,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
public static override get UpdateStateType(): any {
|
|
369
|
+
throw new Error(
|
|
370
|
+
`'UpdateStateType' was called on ${init.tagName} as a value but it is only a type.`,
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
public _initCalled = false;
|
|
375
|
+
public _stateCalled = false;
|
|
376
|
+
public _hasRendered = false;
|
|
377
|
+
public _lastRenderedProps: ThisElementInstance['_lastRenderedProps'] = undefined as any;
|
|
378
|
+
|
|
379
|
+
public render() {
|
|
380
|
+
this._internalRenderCount++;
|
|
381
|
+
try {
|
|
382
|
+
this._hasRendered = true;
|
|
383
|
+
|
|
384
|
+
const renderParams = this.createRenderParams();
|
|
385
|
+
|
|
386
|
+
if (!this._stateCalled && init.state) {
|
|
387
|
+
this._stateCalled = true;
|
|
388
|
+
const stateInit = init.state(renderParams);
|
|
389
|
+
|
|
390
|
+
if (stateInit instanceof Promise) {
|
|
391
|
+
throw new TypeError('init cannot be asynchronous');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
getObjectTypedKeys(stateInit).forEach((stateKey) => {
|
|
395
|
+
bindReactiveProperty(this, stateKey);
|
|
396
|
+
|
|
397
|
+
(this.instanceState as PropertyInitMapBase)[stateKey] = stateInit[stateKey];
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (!this._initCalled && init.init) {
|
|
402
|
+
this._initCalled = true;
|
|
403
|
+
if ((init.init(renderParams) as any) instanceof Promise) {
|
|
404
|
+
throw new TypeError('init cannot be asynchronous');
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const renderResult = typedRenderCallback(renderParams);
|
|
409
|
+
if (renderResult instanceof Promise) {
|
|
410
|
+
throw new TypeError('render cannot be asynchronous');
|
|
411
|
+
}
|
|
412
|
+
applyHostClasses({
|
|
413
|
+
host: renderParams.host,
|
|
414
|
+
hostClassesInit: init.hostClasses,
|
|
415
|
+
hostClassNames,
|
|
416
|
+
state: renderParams.state,
|
|
417
|
+
inputs: renderParams.inputs,
|
|
418
|
+
});
|
|
419
|
+
this._lastRenderedProps = {
|
|
420
|
+
inputs: {...renderParams.inputs},
|
|
421
|
+
state: {...renderParams.state},
|
|
422
|
+
};
|
|
423
|
+
return renderResult;
|
|
424
|
+
} catch (caught) {
|
|
425
|
+
const error: Error = ensureErrorAndPrependMessage(
|
|
426
|
+
caught,
|
|
427
|
+
`Failed to render ${init.tagName}`,
|
|
428
|
+
);
|
|
429
|
+
console.error(error);
|
|
430
|
+
this._lastRenderError = error;
|
|
431
|
+
void elementOptions.errorHandler?.(error);
|
|
432
|
+
return extractErrorMessage(error);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
public override connectedCallback(): void {
|
|
437
|
+
super.connectedCallback();
|
|
438
|
+
if (this._hasRendered && !this._initCalled && init.init) {
|
|
439
|
+
this._initCalled = true;
|
|
440
|
+
const renderParams = this.createRenderParams();
|
|
441
|
+
if ((init.init(renderParams) as any) instanceof Promise) {
|
|
442
|
+
throw new TypeError(`init in '${init.tagName}' cannot be asynchronous`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
public destroy() {
|
|
448
|
+
Object.values(this.instanceState).forEach((stateValue) => {
|
|
449
|
+
if (check.hasKey(stateValue, 'destroy') && check.isFunction(stateValue.destroy)) {
|
|
450
|
+
stateValue.destroy();
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
public override disconnectedCallback(): void {
|
|
456
|
+
super.disconnectedCallback();
|
|
457
|
+
if (init.cleanup) {
|
|
458
|
+
const renderParams = this.createRenderParams();
|
|
459
|
+
if ((init.cleanup(renderParams) as any) instanceof Promise) {
|
|
460
|
+
throw new TypeError(`cleanup in '${init.tagName}' cannot be asynchronous`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
this.destroy();
|
|
464
|
+
this._initCalled = false;
|
|
465
|
+
this._stateCalled = false;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// this is set below in Object.defineProperties
|
|
469
|
+
public readonly definition: ThisElementInstance['definition'] =
|
|
470
|
+
{} as unknown as ThisElementDefinition;
|
|
471
|
+
|
|
472
|
+
public assignInputs(inputs: Partial<Inputs>): void {
|
|
473
|
+
assignInputs(this, inputs);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
public readonly observablePropertyListenerMap: ThisElementInstance['observablePropertyListenerMap'] =
|
|
477
|
+
{};
|
|
478
|
+
|
|
479
|
+
public readonly instanceInputs: ThisElementInstance['instanceInputs'] =
|
|
480
|
+
createElementPropertyProxy<Readonly<Inputs>>(this as any, false);
|
|
481
|
+
|
|
482
|
+
public readonly instanceState: ThisElementInstance['instanceState'] =
|
|
483
|
+
createElementPropertyProxy<State>(this as any, !elementOptions.allowPolymorphicState);
|
|
484
|
+
|
|
485
|
+
constructor() {
|
|
486
|
+
super();
|
|
487
|
+
this.definition = anonymousClass as unknown as ThisElementDefinition;
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
Object.defineProperties(anonymousClass, {
|
|
492
|
+
name: {
|
|
493
|
+
value: kebabCaseToCamelCase(init.tagName, {
|
|
494
|
+
firstLetterCase: StringCase.Upper,
|
|
495
|
+
}),
|
|
496
|
+
writable: true,
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* `window` will be `undefined` in Node.js and we want to be able to import these files into
|
|
502
|
+
* Node.js.
|
|
503
|
+
*/
|
|
504
|
+
if (globalThis.window as typeof window | undefined) {
|
|
505
|
+
if (globalThis.window.customElements.get(init.tagName)) {
|
|
506
|
+
console.warn(
|
|
507
|
+
`Tried to define custom element '${init.tagName}' but it is already defined.`,
|
|
508
|
+
);
|
|
509
|
+
} else {
|
|
510
|
+
globalThis.window.customElements.define(init.tagName, anonymousClass);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return anonymousClass as unknown as ThisElementDefinition;
|
|
515
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {type MaybePromise} from '@augment-vir/common';
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* Extra options for defining elements. These should be used very rarely.
|
|
4
5
|
*
|
|
@@ -13,9 +14,13 @@ export type DeclarativeElementDefinitionOptions = {
|
|
|
13
14
|
/** An error handler that will be called if render errors are encountered. */
|
|
14
15
|
errorHandler: ((error: Error) => MaybePromise<void>) | undefined;
|
|
15
16
|
};
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* Default values for {@link DeclarativeElementDefinitionOptions}.
|
|
18
20
|
*
|
|
19
21
|
* @internal
|
|
20
22
|
*/
|
|
21
|
-
export
|
|
23
|
+
export const defaultDeclarativeElementDefinitionOptions: DeclarativeElementDefinitionOptions = {
|
|
24
|
+
allowPolymorphicState: false,
|
|
25
|
+
errorHandler: undefined,
|
|
26
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {type EmptyObject} from 'type-fest';
|
|
2
|
+
import {
|
|
3
|
+
directive,
|
|
4
|
+
Directive,
|
|
5
|
+
type DirectiveResult,
|
|
6
|
+
noChange,
|
|
7
|
+
type PartInfo,
|
|
8
|
+
} from '../../lit-exports/all-lit-exports.js';
|
|
9
|
+
import {assignInputs} from '../properties/assign-inputs.js';
|
|
10
|
+
import {type PropertyInitMapBase} from '../properties/element-properties.js';
|
|
11
|
+
import {extractElement} from './directive-helpers.js';
|
|
12
|
+
|
|
13
|
+
export type ElementDefinitionWithInputsType<
|
|
14
|
+
InputsType extends PropertyInitMapBase = PropertyInitMapBase,
|
|
15
|
+
> = {InputsType: InputsType};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Assign an object matching an element's inputs to its inputs.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated Instead of using this directive, assign inputs directly on the element's
|
|
21
|
+
* interpolation opening tag interpolation.
|
|
22
|
+
* @example Html`<${MyElement} ${assign(MyElement, {value: 1})}>...` should be
|
|
23
|
+
* html`<${MyElement.assign({value: 1})}>...`
|
|
24
|
+
*/
|
|
25
|
+
export function assign<const SpecificDeclarativeElement extends ElementDefinitionWithInputsType>(
|
|
26
|
+
declarativeElement: SpecificDeclarativeElement,
|
|
27
|
+
inputsObject: EmptyObject extends Required<SpecificDeclarativeElement['InputsType']>
|
|
28
|
+
? never
|
|
29
|
+
: SpecificDeclarativeElement['InputsType'],
|
|
30
|
+
): DirectiveResult;
|
|
31
|
+
/**
|
|
32
|
+
* Assign an object matching an element's inputs to its inputs.
|
|
33
|
+
*
|
|
34
|
+
* @deprecated Instead of using this directive, assign inputs directly on the element's
|
|
35
|
+
* interpolation opening tag interpolation.
|
|
36
|
+
* @example Html`<${MyElement} ${assign(MyElement, {value: 1})}>...` should be
|
|
37
|
+
* html`<${MyElement.assign({value: 1})}>...`
|
|
38
|
+
*/
|
|
39
|
+
export function assign<
|
|
40
|
+
const SpecificDeclarativeElement extends ElementDefinitionWithInputsType,
|
|
41
|
+
const SpecificInput extends SpecificDeclarativeElement['InputsType'],
|
|
42
|
+
>(inputsObject: SpecificInput extends typeof HTMLElement ? never : SpecificInput): DirectiveResult;
|
|
43
|
+
/**
|
|
44
|
+
* Assign an object matching an element's inputs to its inputs.
|
|
45
|
+
*
|
|
46
|
+
* @deprecated Instead of using this directive, assign inputs directly on the element's
|
|
47
|
+
* interpolation opening tag interpolation.
|
|
48
|
+
* @example Html`<${MyElement} ${assign(MyElement, {value: 1})}>...` should be
|
|
49
|
+
* html`<${MyElement.assign({value: 1})}>...`
|
|
50
|
+
*/
|
|
51
|
+
export function assign<const SpecificDeclarativeElement extends ElementDefinitionWithInputsType>(
|
|
52
|
+
declarativeElementOrInputs: SpecificDeclarativeElement,
|
|
53
|
+
inputsObject?: EmptyObject extends Required<SpecificDeclarativeElement['InputsType']>
|
|
54
|
+
? never
|
|
55
|
+
: SpecificDeclarativeElement['InputsType'],
|
|
56
|
+
): DirectiveResult {
|
|
57
|
+
/**
|
|
58
|
+
* The directive generics (in listenDirective) are not strong enough to maintain their values.
|
|
59
|
+
* Thus, the directive call is wrapped in this function.
|
|
60
|
+
*/
|
|
61
|
+
if (inputsObject) {
|
|
62
|
+
return assignDirective(
|
|
63
|
+
declarativeElementOrInputs as ElementDefinitionWithInputsType,
|
|
64
|
+
inputsObject,
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
return assignDirective(undefined, declarativeElementOrInputs as Record<string, any>);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const assignDirective = directive(
|
|
72
|
+
class extends Directive {
|
|
73
|
+
public readonly element: Element;
|
|
74
|
+
|
|
75
|
+
constructor(partInfo: PartInfo) {
|
|
76
|
+
super(partInfo);
|
|
77
|
+
|
|
78
|
+
this.element = extractElement(partInfo, 'assign');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public render(
|
|
82
|
+
elementDefinition: ElementDefinitionWithInputsType | undefined,
|
|
83
|
+
inputsObject: Record<PropertyKey, unknown>,
|
|
84
|
+
) {
|
|
85
|
+
assignInputs(this.element, inputsObject);
|
|
86
|
+
return noChange;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
);
|