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.
- package/README.md +97 -93
- package/dist/augments/testing.d.ts +15 -0
- package/dist/augments/testing.js +76 -0
- package/dist/augments/type.d.ts +7 -0
- package/dist/augments/type.js +13 -1
- package/dist/{functional-element → declarative-element}/css-vars.d.ts +0 -0
- package/dist/{functional-element → declarative-element}/css-vars.js +0 -0
- package/dist/declarative-element/declarative-element-init.d.ts +33 -0
- package/dist/declarative-element/declarative-element-init.js +1 -0
- package/dist/declarative-element/declarative-element.d.ts +44 -0
- package/dist/declarative-element/declarative-element.js +18 -0
- package/dist/declarative-element/define-element-no-inputs.d.ts +5 -0
- package/dist/declarative-element/define-element-no-inputs.js +118 -0
- package/dist/declarative-element/define-element.d.ts +5 -0
- package/dist/declarative-element/define-element.js +13 -0
- package/dist/declarative-element/definition-options.d.ts +5 -0
- package/dist/declarative-element/definition-options.js +4 -0
- package/dist/declarative-element/directives/assign-with-clean-up.directive.d.ts +23 -0
- package/dist/declarative-element/directives/assign-with-clean-up.directive.js +43 -0
- package/dist/declarative-element/directives/assign.directive.d.ts +12 -0
- package/dist/declarative-element/directives/assign.directive.js +35 -0
- package/dist/{functional-element/directives/directive-util.d.ts → declarative-element/directives/directive-helpers.d.ts} +2 -3
- package/dist/{functional-element/directives/directive-util.js → declarative-element/directives/directive-helpers.js} +4 -4
- package/dist/{functional-element → declarative-element}/directives/listen.directive.d.ts +2 -2
- package/dist/{functional-element → declarative-element}/directives/listen.directive.js +1 -1
- package/dist/{functional-element → declarative-element}/directives/on-dom-created.directive.d.ts +0 -0
- package/dist/{functional-element → declarative-element}/directives/on-dom-created.directive.js +1 -1
- package/dist/{functional-element → declarative-element}/directives/on-resize.directive.d.ts +0 -0
- package/dist/{functional-element → declarative-element}/directives/on-resize.directive.js +1 -1
- package/dist/{functional-element → declarative-element}/element-events.d.ts +0 -0
- package/dist/{functional-element → declarative-element}/element-events.js +1 -1
- package/dist/{functional-element → declarative-element}/element-properties.d.ts +3 -3
- package/dist/declarative-element/element-properties.js +53 -0
- package/dist/declarative-element/has-declarative-element-parent.d.ts +1 -0
- package/dist/declarative-element/has-declarative-element-parent.js +16 -0
- package/dist/declarative-element/host-classes.d.ts +21 -0
- package/dist/{functional-element → declarative-element}/host-classes.js +0 -0
- package/dist/declarative-element/render-callback.d.ts +22 -0
- package/dist/{functional-element → declarative-element}/render-callback.js +4 -3
- package/dist/{functional-element → declarative-element}/styles.d.ts +7 -1
- package/dist/{functional-element → declarative-element}/styles.js +2 -2
- package/dist/{functional-element → declarative-element}/tag-name.d.ts +0 -0
- package/dist/{functional-element → declarative-element}/tag-name.js +0 -0
- package/dist/declarative-element-marker-symbol.d.ts +1 -0
- package/dist/declarative-element-marker-symbol.js +1 -0
- package/dist/index.d.ts +14 -12
- package/dist/index.js +13 -12
- package/dist/require-declarative-element.d.ts +2 -0
- package/dist/require-declarative-element.js +4 -0
- package/dist/template-transforms/nested-mapped-templates.d.ts +6 -0
- package/dist/template-transforms/nested-mapped-templates.js +96 -0
- package/dist/template-transforms/transform-template.js +21 -2
- package/dist/template-transforms/vir-css/css-transform.d.ts +2 -2
- package/dist/template-transforms/vir-css/vir-css.d.ts +2 -2
- package/dist/template-transforms/vir-css/vir-css.js +1 -1
- package/dist/template-transforms/vir-html/html-transform.js +3 -3
- package/dist/template-transforms/vir-html/vir-html.d.ts +1 -1
- package/dist/template-transforms/vir-html/vir-html.js +1 -1
- package/index.html +14 -0
- package/package.json +14 -14
- package/public/index.css +7 -0
- package/dist/functional-element/define-functional-element.d.ts +0 -4
- package/dist/functional-element/define-functional-element.js +0 -70
- package/dist/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
- package/dist/functional-element/directives/assign-with-clean-up.directive.js +0 -36
- package/dist/functional-element/directives/assign.directive.d.ts +0 -15
- package/dist/functional-element/directives/assign.directive.js +0 -23
- package/dist/functional-element/element-properties.js +0 -50
- package/dist/functional-element/functional-element.d.ts +0 -57
- package/dist/functional-element/functional-element.js +0 -3
- package/dist/functional-element/host-classes.d.ts +0 -19
- package/dist/functional-element/render-callback.d.ts +0 -21
- package/dist/require-functional-element.d.ts +0 -2
- package/dist/require-functional-element.js +0 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# element-vir
|
|
2
2
|
|
|
3
|
-
Heroic. Reactive.
|
|
3
|
+
Heroic. Reactive. Declarative. Type safe. Web components without compromise.
|
|
4
4
|
|
|
5
5
|
No need for an extra build step,<br>
|
|
6
6
|
no need for side effect imports, <br>
|
|
@@ -11,7 +11,7 @@ _**It's just TypeScript.**_
|
|
|
11
11
|
|
|
12
12
|
Uses the power of _native_ JavaScript custom web elements, _native_ JavaScript template literals, _native_ JavaScript functions<sup>\*</sup>, _native_ HTML, and [lit-element](http://lit.dev).
|
|
13
13
|
|
|
14
|
-
In reality this is basically a [lit-element](http://lit.dev) wrapper that adds type-safe element tag usage and I/O with
|
|
14
|
+
In reality this is basically a [lit-element](http://lit.dev) wrapper that adds type-safe element tag usage and I/O with declarative style component definition.
|
|
15
15
|
|
|
16
16
|
[Works in every major web browser except Internet Explorer.](https://caniuse.com/mdn-api_window_customelements)
|
|
17
17
|
|
|
@@ -29,20 +29,20 @@ Make sure to install this as a normal dependency (not just a dev dependency) bec
|
|
|
29
29
|
|
|
30
30
|
# Usage
|
|
31
31
|
|
|
32
|
-
Most usage of this package is done through the [`
|
|
32
|
+
Most usage of this package is done through the [`defineElementNoInputs` function](https://github.com/electrovir/element-vir/blob/main/src/declarative-element/define-declarative-element.ts#L25-L30). See the [`DeclarativeElementInit` type](https://github.com/electrovir/element-vir/blob/main/src/declarative-element/declarative-element-init.ts#L7-L20) for that function's inputs. These inputs are also described below with examples.
|
|
33
33
|
|
|
34
34
|
All of [`lit`](https://lit.dev)'s syntax and functionality is also available for use if you wish.
|
|
35
35
|
|
|
36
36
|
## Simple element definition
|
|
37
37
|
|
|
38
|
-
Use `
|
|
38
|
+
Use `defineElementNoInputs` to define your element if you're not setting inputs (or just for now as you're getting started). It must be given an object with at least `tagName` and `renderCallback` properties (the types enforce this). Here is a bare-minimum example custom element:
|
|
39
39
|
|
|
40
40
|
<!-- example-link: src/readme-examples/my-simple.element.ts -->
|
|
41
41
|
|
|
42
42
|
```TypeScript
|
|
43
|
-
import {
|
|
43
|
+
import {defineElementNoInputs, html} from 'element-vir';
|
|
44
44
|
|
|
45
|
-
export const MySimpleElement =
|
|
45
|
+
export const MySimpleElement = defineElementNoInputs({
|
|
46
46
|
tagName: 'my-simple-element',
|
|
47
47
|
renderCallback: () => html`
|
|
48
48
|
<span>Hello there!</span>
|
|
@@ -54,15 +54,15 @@ Make sure to export your element definition if you need to use it in other files
|
|
|
54
54
|
|
|
55
55
|
## Using in other elements
|
|
56
56
|
|
|
57
|
-
To use already defined
|
|
57
|
+
To use already defined elements (like `my-simple-element` above), they must be interpolated into HTML templates like so:
|
|
58
58
|
|
|
59
59
|
<!-- example-link: src/readme-examples/my-app.element.ts -->
|
|
60
60
|
|
|
61
61
|
```TypeScript
|
|
62
|
-
import {
|
|
62
|
+
import {defineElementNoInputs, html} from 'element-vir';
|
|
63
63
|
import {MySimpleElement} from './my-simple.element';
|
|
64
64
|
|
|
65
|
-
export const MyAppElement =
|
|
65
|
+
export const MyAppElement = defineElementNoInputs({
|
|
66
66
|
tagName: 'my-app-element',
|
|
67
67
|
renderCallback: () => html`
|
|
68
68
|
<h1>My App</h1>
|
|
@@ -77,14 +77,14 @@ If you wish to bypass this interpolation, make sure to [import the `html` tagged
|
|
|
77
77
|
|
|
78
78
|
## Adding styles
|
|
79
79
|
|
|
80
|
-
Styles are added through the `styles` property when defining a
|
|
80
|
+
Styles are added through the `styles` property when defining a declarative element (similar to [how they are defined in `lit`](https://lit.dev/docs/components/styles/)):
|
|
81
81
|
|
|
82
82
|
<!-- example-link: src/readme-examples/my-simple-app-with-styles.element.ts -->
|
|
83
83
|
|
|
84
84
|
```TypeScript
|
|
85
|
-
import {css,
|
|
85
|
+
import {css, defineElementNoInputs, html} from 'element-vir';
|
|
86
86
|
|
|
87
|
-
export const MySimpleWithStylesElement =
|
|
87
|
+
export const MySimpleWithStylesElement = defineElementNoInputs({
|
|
88
88
|
tagName: 'my-simple-with-styles-element',
|
|
89
89
|
styles: css`
|
|
90
90
|
:host {
|
|
@@ -106,15 +106,15 @@ export const MySimpleWithStylesElement = defineFunctionalElement({
|
|
|
106
106
|
|
|
107
107
|
### Element definition as style selector
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
Declarative element definitions can be used in the `css` tagged template just like in the `html` tagged template. This will be replaced by the element's tag name:
|
|
110
110
|
|
|
111
111
|
<!-- example-link: src/readme-examples/my-simple-app-with-styles-and-interpolated-selector.element.ts -->
|
|
112
112
|
|
|
113
113
|
```TypeScript
|
|
114
|
-
import {css,
|
|
114
|
+
import {css, defineElementNoInputs, html} from 'element-vir';
|
|
115
115
|
import {MySimpleElement} from './my-simple.element';
|
|
116
116
|
|
|
117
|
-
export const MySimpleWithStylesAndInterpolatedSelectorElement =
|
|
117
|
+
export const MySimpleWithStylesAndInterpolatedSelectorElement = defineElementNoInputs({
|
|
118
118
|
tagName: 'my-simple-with-styles-and-interpolated-selector-element',
|
|
119
119
|
styles: css`
|
|
120
120
|
${MySimpleElement} {
|
|
@@ -127,51 +127,50 @@ export const MySimpleWithStylesAndInterpolatedSelectorElement = defineFunctional
|
|
|
127
127
|
});
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
## Defining and using
|
|
130
|
+
## Defining and using Inputs
|
|
131
131
|
|
|
132
|
-
Define element
|
|
132
|
+
Define element inputs by using `defineElement` to define a declarative element. Pass your input type as a generic to the `defineElement` call. Then call _that_ with the normal definition input (like when using `defineElementNoInputs`).
|
|
133
133
|
|
|
134
|
-
To use
|
|
134
|
+
To use an element's inputs for use in its template, grab `inputs` from `renderCallback`'s parameters and interpolate it into your HTML template:
|
|
135
135
|
|
|
136
|
-
<!-- example-link: src/readme-examples/my-simple-with-
|
|
136
|
+
<!-- example-link: src/readme-examples/my-simple-with-inputs.element.ts -->
|
|
137
137
|
|
|
138
138
|
```TypeScript
|
|
139
|
-
import {
|
|
140
|
-
|
|
141
|
-
export const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
<span>Hello there ${props.currentUsername}!</span>
|
|
139
|
+
import {defineElement, html} from 'element-vir';
|
|
140
|
+
|
|
141
|
+
export const MySimpleWithInputsElement = defineElement<{
|
|
142
|
+
username: string;
|
|
143
|
+
email: string;
|
|
144
|
+
}>()({
|
|
145
|
+
tagName: 'my-simple-element-with-inputs',
|
|
146
|
+
renderCallback: ({inputs}) => html`
|
|
147
|
+
<span>Hello there ${inputs.username}!</span>
|
|
149
148
|
`,
|
|
150
149
|
});
|
|
151
150
|
```
|
|
152
151
|
|
|
153
|
-
|
|
152
|
+
## Defining internal state
|
|
154
153
|
|
|
155
|
-
|
|
154
|
+
Define internal state with the `stateInit` property when defining an element. Grab it with `state` in `renderCallback` to use state. Grab `updateState` in `renderCallback` to update state:
|
|
156
155
|
|
|
157
|
-
<!-- example-link: src/readme-examples/my-simple-with-
|
|
156
|
+
<!-- example-link: src/readme-examples/my-simple-with-update-state.element.ts -->
|
|
158
157
|
|
|
159
158
|
```TypeScript
|
|
160
|
-
import {
|
|
159
|
+
import {defineElementNoInputs, html, listen} from 'element-vir';
|
|
161
160
|
|
|
162
|
-
export const
|
|
163
|
-
tagName: 'my-simple-element-with-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
export const MySimpleWithUpdateStateElement = defineElementNoInputs({
|
|
162
|
+
tagName: 'my-simple-element-with-update-state',
|
|
163
|
+
stateInit: {
|
|
164
|
+
username: 'dev',
|
|
165
|
+
email: undefined as string | undefined,
|
|
167
166
|
},
|
|
168
|
-
renderCallback: ({
|
|
167
|
+
renderCallback: ({state, updateState}) => html`
|
|
169
168
|
<span
|
|
170
169
|
${listen('click', () => {
|
|
171
|
-
|
|
170
|
+
updateState({username: 'new name!'});
|
|
172
171
|
})}
|
|
173
172
|
>
|
|
174
|
-
Hello there ${
|
|
173
|
+
Hello there ${state.username}!
|
|
175
174
|
</span>
|
|
176
175
|
`,
|
|
177
176
|
});
|
|
@@ -181,37 +180,39 @@ export const MySimpleWithPropsElement = defineFunctionalElement({
|
|
|
181
180
|
|
|
182
181
|
Use the `assign` directive to assign properties to child custom elements:
|
|
183
182
|
|
|
184
|
-
<!-- example-link: src/readme-examples/my-app-with-
|
|
183
|
+
<!-- example-link: src/readme-examples/my-app-with-assignment.element.ts -->
|
|
185
184
|
|
|
186
185
|
```TypeScript
|
|
187
|
-
import {assign,
|
|
188
|
-
import {
|
|
186
|
+
import {assign, defineElementNoInputs, html} from 'element-vir';
|
|
187
|
+
import {MySimpleWithInputsElement} from './my-simple-with-inputs.element';
|
|
189
188
|
|
|
190
|
-
export const
|
|
191
|
-
tagName: 'my-app-with-
|
|
189
|
+
export const MyAppWithAssignmentElement = defineElementNoInputs({
|
|
190
|
+
tagName: 'my-app-with-assignment-element',
|
|
192
191
|
renderCallback: () => html`
|
|
193
192
|
<h1>My App</h1>
|
|
194
|
-
<${
|
|
195
|
-
${assign(
|
|
196
|
-
|
|
193
|
+
<${MySimpleWithInputsElement}
|
|
194
|
+
${assign(MySimpleWithInputsElement, {
|
|
195
|
+
email: 'user@example.com',
|
|
196
|
+
username: 'user',
|
|
197
|
+
})}
|
|
197
198
|
>
|
|
198
|
-
</${
|
|
199
|
+
</${MySimpleWithInputsElement}>
|
|
199
200
|
`,
|
|
200
201
|
});
|
|
201
202
|
```
|
|
202
203
|
|
|
203
204
|
## Element events (outputs)
|
|
204
205
|
|
|
205
|
-
Define events with `events` when
|
|
206
|
+
Define events with `events` when defining a declarative element. Each event must be initialized with `defineElementEvent` and a type parameter. `defineElementEvent` accepts no inputs as it doesn't make sense for events to have default values.
|
|
206
207
|
|
|
207
208
|
To dispatch an event, grab `dispatch` from `renderCallback`'s parameters.
|
|
208
209
|
|
|
209
210
|
<!-- example-link: src/readme-examples/my-simple-with-events.element.ts -->
|
|
210
211
|
|
|
211
212
|
```TypeScript
|
|
212
|
-
import {defineElementEvent,
|
|
213
|
+
import {defineElementEvent, defineElementNoInputs, html, listen} from 'element-vir';
|
|
213
214
|
|
|
214
|
-
export const MySimpleWithEventsElement =
|
|
215
|
+
export const MySimpleWithEventsElement = defineElementNoInputs({
|
|
215
216
|
tagName: 'my-simple-element-with-events',
|
|
216
217
|
events: {
|
|
217
218
|
logoutClick: defineElementEvent<void>(),
|
|
@@ -230,31 +231,31 @@ export const MySimpleWithEventsElement = defineFunctionalElement({
|
|
|
230
231
|
|
|
231
232
|
### Listening to typed events (outputs)
|
|
232
233
|
|
|
233
|
-
Use the `listen` directive to listen to typed events emitted by your custom
|
|
234
|
+
Use the `listen` directive to listen to typed events emitted by your custom elements:
|
|
234
235
|
|
|
235
236
|
<!-- example-link: src/readme-examples/my-app-with-events.element.ts -->
|
|
236
237
|
|
|
237
238
|
```TypeScript
|
|
238
|
-
import {
|
|
239
|
+
import {defineElementNoInputs, html, listen} from 'element-vir';
|
|
239
240
|
import {MySimpleWithEventsElement} from './my-simple-with-events.element';
|
|
240
241
|
|
|
241
|
-
export const MyAppWithEventsElement =
|
|
242
|
+
export const MyAppWithEventsElement = defineElementNoInputs({
|
|
242
243
|
tagName: 'my-app-with-events-element',
|
|
243
|
-
|
|
244
|
+
stateInit: {
|
|
244
245
|
myNumber: -1,
|
|
245
246
|
},
|
|
246
|
-
renderCallback: ({
|
|
247
|
+
renderCallback: ({state, updateState}) => html`
|
|
247
248
|
<h1>My App</h1>
|
|
248
249
|
<${MySimpleWithEventsElement}
|
|
249
250
|
${listen(MySimpleWithEventsElement.events.logoutClick, () => {
|
|
250
251
|
console.info('logout triggered');
|
|
251
252
|
})}
|
|
252
253
|
${listen(MySimpleWithEventsElement.events.randomNumber, (event) => {
|
|
253
|
-
|
|
254
|
+
updateState({myNumber: event.detail});
|
|
254
255
|
})}
|
|
255
256
|
>
|
|
256
257
|
</${MySimpleWithEventsElement}>
|
|
257
|
-
<span>${
|
|
258
|
+
<span>${state.myNumber}</span>
|
|
258
259
|
`,
|
|
259
260
|
});
|
|
260
261
|
```
|
|
@@ -282,15 +283,15 @@ Both dispatching a custom event and listening to a custom event:
|
|
|
282
283
|
<!-- example-link: src/readme-examples/custom-event-usage.element.ts -->
|
|
283
284
|
|
|
284
285
|
```TypeScript
|
|
285
|
-
import {
|
|
286
|
+
import {defineElementNoInputs, html, listen} from 'element-vir';
|
|
286
287
|
import {MyCustomEvent} from './custom-event-no-element';
|
|
287
288
|
|
|
288
|
-
export const MyElementWithCustomEvents =
|
|
289
|
+
export const MyElementWithCustomEvents = defineElementNoInputs({
|
|
289
290
|
tagName: 'my-app-with-custom-events',
|
|
290
291
|
renderCallback: ({genericDispatch}) => html`
|
|
291
292
|
<div
|
|
292
293
|
${listen(MyCustomEvent, (event) => {
|
|
293
|
-
console.
|
|
294
|
+
console.info(`Got a number! ${event.detail}`);
|
|
294
295
|
})}
|
|
295
296
|
>
|
|
296
297
|
<div
|
|
@@ -314,11 +315,11 @@ Apply host classes in the element's stylesheet by using a callback for the style
|
|
|
314
315
|
<!-- example-link: src/readme-examples/host-class-definition.ts -->
|
|
315
316
|
|
|
316
317
|
```TypeScript
|
|
317
|
-
import {css,
|
|
318
|
+
import {css, defineElementNoInputs, html} from 'element-vir';
|
|
318
319
|
|
|
319
|
-
export const MyAppWithHostClasses =
|
|
320
|
+
export const MyAppWithHostClasses = defineElementNoInputs({
|
|
320
321
|
tagName: 'my-app-with-host-classes',
|
|
321
|
-
|
|
322
|
+
stateInit: {
|
|
322
323
|
myProp: 'hello there',
|
|
323
324
|
},
|
|
324
325
|
hostClasses: {
|
|
@@ -331,8 +332,8 @@ export const MyAppWithHostClasses = defineFunctionalElement({
|
|
|
331
332
|
* This host class will be automatically applied if the given callback evaluated to true
|
|
332
333
|
* after a call to renderCallback.
|
|
333
334
|
*/
|
|
334
|
-
automaticallyAppliedVariation: ({
|
|
335
|
-
return
|
|
335
|
+
automaticallyAppliedVariation: ({state}) => {
|
|
336
|
+
return state.myProp === 'foo';
|
|
336
337
|
},
|
|
337
338
|
},
|
|
338
339
|
/**
|
|
@@ -348,8 +349,8 @@ export const MyAppWithHostClasses = defineFunctionalElement({
|
|
|
348
349
|
color: red;
|
|
349
350
|
}
|
|
350
351
|
`,
|
|
351
|
-
renderCallback: ({
|
|
352
|
-
${
|
|
352
|
+
renderCallback: ({state}) => html`
|
|
353
|
+
${state.myProp}
|
|
353
354
|
`,
|
|
354
355
|
});
|
|
355
356
|
```
|
|
@@ -361,9 +362,9 @@ Typed CSS vars are created in a similar way as host classes:
|
|
|
361
362
|
<!-- example-link: src/readme-examples/css-vars-definition.ts -->
|
|
362
363
|
|
|
363
364
|
```TypeScript
|
|
364
|
-
import {css,
|
|
365
|
+
import {css, defineElementNoInputs, html} from 'element-vir';
|
|
365
366
|
|
|
366
|
-
export const MyAppWithCssVars =
|
|
367
|
+
export const MyAppWithCssVars = defineElementNoInputs({
|
|
367
368
|
tagName: 'my-app-with-css-vars',
|
|
368
369
|
cssVars: {
|
|
369
370
|
/**
|
|
@@ -397,15 +398,15 @@ This triggers only once when the element it's attached has actually been created
|
|
|
397
398
|
<!-- example-link: src/readme-examples/my-simple-with-on-dom-created.element.ts -->
|
|
398
399
|
|
|
399
400
|
```TypeScript
|
|
400
|
-
import {
|
|
401
|
+
import {defineElementNoInputs, html, onDomCreated} from 'element-vir';
|
|
401
402
|
|
|
402
|
-
export const MySimpleWithOnDomCreatedElement =
|
|
403
|
+
export const MySimpleWithOnDomCreatedElement = defineElementNoInputs({
|
|
403
404
|
tagName: 'my-simple-with-on-dom-created-element',
|
|
404
405
|
renderCallback: () => html`
|
|
405
406
|
<span
|
|
406
407
|
${onDomCreated((element) => {
|
|
407
408
|
// logs a span element
|
|
408
|
-
console.
|
|
409
|
+
console.info(element);
|
|
409
410
|
})}
|
|
410
411
|
>
|
|
411
412
|
Hello there!
|
|
@@ -421,16 +422,16 @@ This directive fulfills a common use case of triggering callbacks when something
|
|
|
421
422
|
<!-- example-link: src/readme-examples/my-simple-with-on-resize.element.ts -->
|
|
422
423
|
|
|
423
424
|
```TypeScript
|
|
424
|
-
import {
|
|
425
|
+
import {defineElementNoInputs, html, onResize} from 'element-vir';
|
|
425
426
|
|
|
426
|
-
export const MySimpleWithOnResizeElement =
|
|
427
|
+
export const MySimpleWithOnResizeElement = defineElementNoInputs({
|
|
427
428
|
tagName: 'my-simple-with-on-dom-created-element',
|
|
428
429
|
renderCallback: () => html`
|
|
429
430
|
<span
|
|
430
431
|
${onResize((entry) => {
|
|
431
432
|
// this will track resizing of this span
|
|
432
433
|
// the entry parameter contains target and contentRect properties
|
|
433
|
-
console.
|
|
434
|
+
console.info(entry);
|
|
434
435
|
})}
|
|
435
436
|
>
|
|
436
437
|
Hello there!
|
|
@@ -454,40 +455,43 @@ This directive is the same as the `assign` directive but it accepts an additiona
|
|
|
454
455
|
<!-- example-link: src/readme-examples/my-app-with-cleanup.element.ts -->
|
|
455
456
|
|
|
456
457
|
```TypeScript
|
|
457
|
-
import {
|
|
458
|
-
import {
|
|
458
|
+
import {assignWithCleanup, defineElementNoInputs, html} from 'element-vir';
|
|
459
|
+
import {MySimpleWithInputsElement} from './my-simple-with-inputs.element';
|
|
459
460
|
|
|
460
|
-
export const
|
|
461
|
+
export const MyAppWithAssignmentCleanupElement = defineElementNoInputs({
|
|
461
462
|
tagName: 'my-app-with-cleanup',
|
|
462
463
|
renderCallback: () => html`
|
|
463
464
|
<h1>My App</h1>
|
|
464
|
-
<${
|
|
465
|
+
<${MySimpleWithInputsElement}
|
|
465
466
|
${assignWithCleanup(
|
|
466
|
-
|
|
467
|
-
|
|
467
|
+
MySimpleWithInputsElement,
|
|
468
|
+
{
|
|
469
|
+
email: 'user@example.com',
|
|
470
|
+
username: 'user',
|
|
471
|
+
},
|
|
468
472
|
(previousValue) => {
|
|
469
473
|
// here would be the cleanup code.
|
|
470
|
-
// In this specific example the value is just a string, so no cleanup is needed
|
|
471
|
-
|
|
474
|
+
// In this specific example the value is just a string, so no cleanup is needed
|
|
475
|
+
// and the following line isn't actually doing anything.
|
|
476
|
+
previousValue.username.trim();
|
|
472
477
|
},
|
|
473
478
|
)}
|
|
474
|
-
${assign(MySimpleWithPropsElement.props.currentEmail, 'user@example.com')}
|
|
475
479
|
>
|
|
476
|
-
</${
|
|
480
|
+
</${MySimpleWithInputsElement}>
|
|
477
481
|
`,
|
|
478
482
|
});
|
|
479
483
|
```
|
|
480
484
|
|
|
481
|
-
## Require all child custom elements to be
|
|
485
|
+
## Require all child custom elements to be declarative elements
|
|
482
486
|
|
|
483
|
-
To require all child elements to be
|
|
487
|
+
To require all child elements to be declarative elements defined by this package, call `requireAllCustomElementsToBeDeclarativeElements` anywhere in your app. This is a global setting so do not enable it unless you want it to be true _everywhere_ in your current run-time. This should not be used if you're using custom elements from other libraries (unless they happen to also use this package to define their custom elements).
|
|
484
488
|
|
|
485
|
-
<!-- example-link: src/readme-examples/require-
|
|
489
|
+
<!-- example-link: src/readme-examples/require-declarative-element.ts -->
|
|
486
490
|
|
|
487
491
|
```TypeScript
|
|
488
|
-
import {
|
|
492
|
+
import {requireAllCustomElementsToBeDeclarativeElements} from 'element-vir';
|
|
489
493
|
|
|
490
|
-
|
|
494
|
+
requireAllCustomElementsToBeDeclarativeElements();
|
|
491
495
|
```
|
|
492
496
|
|
|
493
497
|
# Dev
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DeclarativeElementDefinition } from '../declarative-element/declarative-element';
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper for assert.instanceOf that also works with TypeScript in setting the proper types.
|
|
4
|
+
*
|
|
5
|
+
* Do not use this in production code! It should only be used in testing code.
|
|
6
|
+
*/
|
|
7
|
+
export declare function assertInstanceOf<T>(value: unknown, constructor: new (...args: any) => T, message?: string): asserts value is T;
|
|
8
|
+
export declare function isInstanceOf<T>(value: unknown, constructor: new (...args: any) => T): value is T;
|
|
9
|
+
export declare function getAssertedDeclarativeElement<DeclarativeElementGeneric extends DeclarativeElementDefinition>(searchFor: DeclarativeElementGeneric, searchIn: Element): DeclarativeElementGeneric['instanceType'];
|
|
10
|
+
export declare function testIdSelector(testId: string): string;
|
|
11
|
+
export declare function getCenterOfElement(element: Element): [number, number];
|
|
12
|
+
export declare function queryWithAssert<T extends Element>(query: string | [string, ...string[]], constructor: new (...args: any) => T, searchIn: Element | Document): T;
|
|
13
|
+
export declare function assertRejects(input: () => PromiseLike<any>, message?: string): Promise<void>;
|
|
14
|
+
export declare function assertRejects(input: () => PromiseLike<any>, errType: RegExp | ErrorConstructor, message?: string): Promise<void>;
|
|
15
|
+
export declare function assertRejects(input: () => PromiseLike<any>, errType: ErrorConstructor, regExp: RegExp): Promise<void>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { assert } from '@open-wc/testing';
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper for assert.instanceOf that also works with TypeScript in setting the proper types.
|
|
4
|
+
*
|
|
5
|
+
* Do not use this in production code! It should only be used in testing code.
|
|
6
|
+
*/
|
|
7
|
+
export function assertInstanceOf(value, constructor, message) {
|
|
8
|
+
assert.instanceOf(value, constructor, message);
|
|
9
|
+
}
|
|
10
|
+
export function isInstanceOf(value, constructor) {
|
|
11
|
+
return value instanceof constructor;
|
|
12
|
+
}
|
|
13
|
+
export function getAssertedDeclarativeElement(searchFor, searchIn) {
|
|
14
|
+
if (searchIn.tagName.toLowerCase() === searchFor.tagName.toLowerCase()) {
|
|
15
|
+
assertInstanceOf(searchIn, searchFor);
|
|
16
|
+
return searchIn;
|
|
17
|
+
}
|
|
18
|
+
const result = queryTree(searchIn, [searchFor.tagName]);
|
|
19
|
+
assertInstanceOf(result, searchFor);
|
|
20
|
+
assert.strictEqual(result.tagName, searchFor.tagName);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
export function testIdSelector(testId) {
|
|
24
|
+
return `[data-test-id="${testId}"]`;
|
|
25
|
+
}
|
|
26
|
+
export function getCenterOfElement(element) {
|
|
27
|
+
const rect = element.getBoundingClientRect();
|
|
28
|
+
return [
|
|
29
|
+
Math.floor((rect.left + rect.right) / 2),
|
|
30
|
+
Math.floor((rect.bottom + rect.top) / 2),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
export function queryWithAssert(query, constructor, searchIn) {
|
|
34
|
+
if (!Array.isArray(query)) {
|
|
35
|
+
query = [query];
|
|
36
|
+
}
|
|
37
|
+
const result = queryTree(searchIn, query);
|
|
38
|
+
assertInstanceOf(result, constructor);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
/** Accounts for shadow DOM */
|
|
42
|
+
function queryTree(context,
|
|
43
|
+
// at least one string is required or this function makes no sense
|
|
44
|
+
selectors) {
|
|
45
|
+
/**
|
|
46
|
+
* The callback is split out here to appease the Type Gods. Without it, finalElement will be the
|
|
47
|
+
* type of the internal currentContext (which is incorrect).
|
|
48
|
+
*/
|
|
49
|
+
const reduceCallback = (currentContext, selector) => {
|
|
50
|
+
var _a;
|
|
51
|
+
if (!currentContext) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
if ('shadowRoot' in currentContext && currentContext.shadowRoot) {
|
|
55
|
+
currentContext = currentContext.shadowRoot;
|
|
56
|
+
}
|
|
57
|
+
return (_a = currentContext.querySelector(selector)) !== null && _a !== void 0 ? _a : undefined;
|
|
58
|
+
};
|
|
59
|
+
const finalElement = selectors.reduce(reduceCallback, context);
|
|
60
|
+
return finalElement;
|
|
61
|
+
}
|
|
62
|
+
export async function assertRejects(input, messageOrRegExpOrError, messageOrRegExp) {
|
|
63
|
+
let thrown = undefined;
|
|
64
|
+
let errorThrown = false;
|
|
65
|
+
try {
|
|
66
|
+
await input();
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
errorThrown = true;
|
|
70
|
+
thrown = error;
|
|
71
|
+
}
|
|
72
|
+
assert.isTrue(errorThrown, 'No error was thrown.');
|
|
73
|
+
assert.throws(() => {
|
|
74
|
+
throw thrown;
|
|
75
|
+
}, messageOrRegExpOrError, messageOrRegExp);
|
|
76
|
+
}
|
package/dist/augments/type.d.ts
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
1
|
export declare type NonEmptyString<T> = T extends '' ? never : T;
|
|
2
|
+
/**
|
|
3
|
+
* If the given value is not an instance of the given constructor, an error is thrown.
|
|
4
|
+
*
|
|
5
|
+
* This is a variation of assertInstanceOf that can be run in run-time code and doesn't require
|
|
6
|
+
* testing packages.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ensureInstanceOf<T>(value: unknown, constructor: new (...args: any) => T, message?: string): asserts value is T;
|
package/dist/augments/type.js
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* If the given value is not an instance of the given constructor, an error is thrown.
|
|
3
|
+
*
|
|
4
|
+
* This is a variation of assertInstanceOf that can be run in run-time code and doesn't require
|
|
5
|
+
* testing packages.
|
|
6
|
+
*/
|
|
7
|
+
export function ensureInstanceOf(value, constructor, message) {
|
|
8
|
+
if (!(value instanceof constructor)) {
|
|
9
|
+
const extraMessage = message ? `: ${message}` : '';
|
|
10
|
+
const errorMessage = `${value} is not an instanceof of ${constructor.name}${extraMessage}`;
|
|
11
|
+
throw new TypeError(errorMessage);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CSSResult } from 'lit';
|
|
2
|
+
import { CssVarsInitMap } from './css-vars';
|
|
3
|
+
import { DeclarativeElementDefinitionOptions } from './definition-options';
|
|
4
|
+
import { EventsInitMap } from './element-events';
|
|
5
|
+
import { PropertyInitMapBase } from './element-properties';
|
|
6
|
+
import { HostClassesInitMap } from './host-classes';
|
|
7
|
+
import { InitCallback, RenderCallback } from './render-callback';
|
|
8
|
+
import { StylesCallback } from './styles';
|
|
9
|
+
export declare type CustomElementTagName = `${string}-${string}`;
|
|
10
|
+
export declare type DeclarativeElementInit<InputsGeneric extends PropertyInitMapBase, StateInit extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> = {
|
|
11
|
+
/**
|
|
12
|
+
* HTML tag name. This should not be used directly, as interpolating it with the html tagged
|
|
13
|
+
* template from this package is preferred.
|
|
14
|
+
*/
|
|
15
|
+
tagName: CustomElementTagName;
|
|
16
|
+
/** Static styles. These should not and cannot change. */
|
|
17
|
+
styles?: CSSResult | StylesCallback<HostClassKeys, CssVarKeys>;
|
|
18
|
+
/** Element properties. (These can be thought of as "inputs".) */
|
|
19
|
+
stateInit?: StateInit;
|
|
20
|
+
/** Events that the element can dispatch. (These can be thought of as "outputs".) */
|
|
21
|
+
events?: EventsInitGeneric;
|
|
22
|
+
/**
|
|
23
|
+
* CSS host classes. Values can be callbacks to determine when a host class should be defined,
|
|
24
|
+
* based on current instance state or inputs, or just undefined to indicate that the host class
|
|
25
|
+
* will only be manually set.
|
|
26
|
+
*/
|
|
27
|
+
hostClasses?: HostClassesInitMap<HostClassKeys, InputsGeneric, StateInit>;
|
|
28
|
+
cssVars?: CssVarsInitMap<CssVarKeys>;
|
|
29
|
+
/** Called as part of the first renderCallback call, before the first renderCallback call. */
|
|
30
|
+
initCallback?: InitCallback<InputsGeneric, StateInit, EventsInitGeneric, HostClassKeys, CssVarKeys>;
|
|
31
|
+
renderCallback: RenderCallback<InputsGeneric, StateInit, EventsInitGeneric, HostClassKeys, CssVarKeys>;
|
|
32
|
+
options?: Partial<DeclarativeElementDefinitionOptions> | undefined;
|
|
33
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RequiredBy } from 'augment-vir';
|
|
2
|
+
import { CSSResult, LitElement, TemplateResult } from 'lit';
|
|
3
|
+
import { CssVarNameOrValueMap } from './css-vars';
|
|
4
|
+
import { DeclarativeElementInit } from './declarative-element-init';
|
|
5
|
+
import { EventDescriptorMap, EventsInitMap } from './element-events';
|
|
6
|
+
import { ElementPropertyDescriptorMap, PropertyInitMapBase } from './element-properties';
|
|
7
|
+
import { HostClassNamesMap } from './host-classes';
|
|
8
|
+
import { RenderCallback } from './render-callback';
|
|
9
|
+
export declare type DeclarativeElementDefinition<InputsGeneric extends PropertyInitMapBase = any, PropertyInitGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = string, CssVarKeys extends string = string> = (new () => DeclarativeElement<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>) & StaticDeclarativeElementProperties<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys> & {
|
|
10
|
+
instanceType: DeclarativeElement<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
|
|
11
|
+
};
|
|
12
|
+
export declare abstract class DeclarativeElement<InputsGeneric extends PropertyInitMapBase = any, PropertyInitGeneric extends PropertyInitMapBase = any, EventsInitGeneric extends EventsInitMap = any, HostClassKeys extends string = string, CssVarKeys extends string = string> extends LitElement {
|
|
13
|
+
static readonly tagName: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['tagName'];
|
|
14
|
+
static readonly styles: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['styles'];
|
|
15
|
+
static readonly isStrictInstance: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['isStrictInstance'];
|
|
16
|
+
static readonly renderCallback: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['renderCallback'];
|
|
17
|
+
static readonly inputsType: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['inputsType'];
|
|
18
|
+
static readonly events: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['events'];
|
|
19
|
+
static readonly stateInit: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['stateInit'];
|
|
20
|
+
static readonly init: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['init'];
|
|
21
|
+
static readonly hostClasses: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['hostClasses'];
|
|
22
|
+
static readonly cssVarNames: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['cssVarNames'];
|
|
23
|
+
static readonly cssVarValues: StaticDeclarativeElementProperties<PropertyInitMapBase, PropertyInitMapBase, EventsInitMap, string, string>['cssVarValues'];
|
|
24
|
+
abstract render(): TemplateResult | Promise<TemplateResult>;
|
|
25
|
+
abstract readonly instanceState: PropertyInitGeneric;
|
|
26
|
+
abstract readonly instanceInputs: InputsGeneric;
|
|
27
|
+
abstract readonly haveInputsBeenSet: boolean;
|
|
28
|
+
abstract markInputsAsHavingBeenSet(): void;
|
|
29
|
+
abstract readonly creator: DeclarativeElementDefinition<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
|
|
30
|
+
}
|
|
31
|
+
export interface StaticDeclarativeElementProperties<InputsGeneric extends PropertyInitMapBase, PropertyInitGeneric extends PropertyInitMapBase, EventsInitGeneric extends EventsInitMap, HostClassKeys extends string, CssVarKeys extends string> {
|
|
32
|
+
/** Pass through the render callback for direct unit testability */
|
|
33
|
+
readonly renderCallback: RenderCallback<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
|
|
34
|
+
events: EventDescriptorMap<EventsInitGeneric>;
|
|
35
|
+
stateInit: ElementPropertyDescriptorMap<PropertyInitGeneric>;
|
|
36
|
+
init: RequiredBy<DeclarativeElementInit<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>, 'stateInit' | 'events'>;
|
|
37
|
+
inputsType: InputsGeneric;
|
|
38
|
+
isStrictInstance: (element: unknown) => element is DeclarativeElement<InputsGeneric, PropertyInitGeneric, EventsInitGeneric, HostClassKeys, CssVarKeys>;
|
|
39
|
+
hostClasses: HostClassNamesMap<string, HostClassKeys>;
|
|
40
|
+
cssVarNames: CssVarNameOrValueMap<CssVarKeys>;
|
|
41
|
+
cssVarValues: CssVarNameOrValueMap<CssVarKeys>;
|
|
42
|
+
tagName: string;
|
|
43
|
+
styles: CSSResult;
|
|
44
|
+
}
|