element-vir 5.5.1 → 6.0.0-beta.1
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 +171 -86
- package/dist/{cjs/augments → augments}/array.d.ts +0 -0
- package/dist/{esm/augments → augments}/array.js +0 -0
- package/dist/augments/testing.d.ts +15 -0
- package/dist/augments/testing.js +76 -0
- package/dist/augments/type.d.ts +8 -0
- package/dist/augments/type.js +13 -0
- package/dist/declarative-element/css-vars.d.ts +6 -0
- package/dist/declarative-element/css-vars.js +22 -0
- package/dist/declarative-element/declarative-element-init.d.ts +33 -0
- package/dist/{esm/augments/type.js → declarative-element/declarative-element-init.js} +0 -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 +117 -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/{esm/functional-element/directives/directive-util.d.ts → declarative-element/directives/directive-helpers.d.ts} +2 -3
- package/dist/{esm/functional-element/directives/directive-util.js → declarative-element/directives/directive-helpers.js} +4 -4
- package/dist/{types/functional-element → declarative-element}/directives/listen.directive.d.ts +2 -2
- package/dist/{esm/functional-element → declarative-element}/directives/listen.directive.js +1 -1
- package/dist/{cjs/functional-element → declarative-element}/directives/on-dom-created.directive.d.ts +0 -0
- package/dist/{esm/functional-element → declarative-element}/directives/on-dom-created.directive.js +1 -1
- package/dist/{cjs/functional-element → declarative-element}/directives/on-resize.directive.d.ts +0 -0
- package/dist/{esm/functional-element → declarative-element}/directives/on-resize.directive.js +1 -1
- package/dist/{cjs/functional-element → declarative-element}/element-events.d.ts +0 -0
- package/dist/{esm/functional-element → declarative-element}/element-events.js +1 -1
- package/dist/{esm/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/declarative-element/host-classes.js +12 -0
- package/dist/declarative-element/render-callback.d.ts +22 -0
- package/dist/{esm/functional-element → declarative-element}/render-callback.js +4 -3
- package/dist/declarative-element/styles.d.ts +22 -0
- package/dist/declarative-element/styles.js +29 -0
- package/dist/declarative-element/tag-name.d.ts +2 -0
- package/dist/declarative-element/tag-name.js +4 -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 +17 -0
- package/dist/index.js +16 -0
- package/dist/require-declarative-element.d.ts +2 -0
- package/dist/require-declarative-element.js +4 -0
- package/dist/{cjs/template-transforms → template-transforms}/has-static-tag-name.d.ts +0 -0
- package/dist/{esm/template-transforms → template-transforms}/has-static-tag-name.js +0 -0
- package/dist/template-transforms/nested-mapped-templates.d.ts +6 -0
- package/dist/template-transforms/nested-mapped-templates.js +96 -0
- package/dist/{cjs/template-transforms → template-transforms}/transform-template.d.ts +0 -0
- package/dist/{esm/template-transforms → template-transforms}/transform-template.js +21 -2
- package/dist/{cjs/template-transforms → template-transforms}/vir-css/css-transform.d.ts +2 -2
- package/dist/{esm/template-transforms → template-transforms}/vir-css/css-transform.js +0 -0
- package/dist/template-transforms/vir-css/vir-css.d.ts +3 -0
- package/dist/{esm/template-transforms → template-transforms}/vir-css/vir-css.js +1 -1
- package/dist/{cjs/template-transforms → template-transforms}/vir-html/html-transform.d.ts +0 -0
- package/dist/{esm/template-transforms → template-transforms}/vir-html/html-transform.js +3 -3
- package/dist/{types/template-transforms → template-transforms}/vir-html/vir-html.d.ts +1 -1
- package/dist/{esm/template-transforms → template-transforms}/vir-html/vir-html.js +1 -1
- package/dist/{cjs/typed-event → typed-event}/typed-event.d.ts +0 -0
- package/dist/{esm/typed-event → typed-event}/typed-event.js +0 -0
- package/index.html +14 -0
- package/package.json +17 -18
- package/public/index.css +7 -0
- package/dist/cjs/augments/array.js +0 -7
- package/dist/cjs/augments/type.d.ts +0 -1
- package/dist/cjs/augments/type.js +0 -2
- package/dist/cjs/functional-element/define-functional-element.d.ts +0 -4
- package/dist/cjs/functional-element/define-functional-element.js +0 -51
- package/dist/cjs/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
- package/dist/cjs/functional-element/directives/assign-with-clean-up.directive.js +0 -40
- package/dist/cjs/functional-element/directives/assign.directive.d.ts +0 -15
- package/dist/cjs/functional-element/directives/assign.directive.js +0 -27
- package/dist/cjs/functional-element/directives/directive-util.d.ts +0 -15
- package/dist/cjs/functional-element/directives/directive-util.js +0 -27
- package/dist/cjs/functional-element/directives/listen.directive.d.ts +0 -13
- package/dist/cjs/functional-element/directives/listen.directive.js +0 -51
- package/dist/cjs/functional-element/directives/on-dom-created.directive.js +0 -26
- package/dist/cjs/functional-element/directives/on-resize.directive.js +0 -39
- package/dist/cjs/functional-element/element-events.js +0 -29
- package/dist/cjs/functional-element/element-properties.d.ts +0 -16
- package/dist/cjs/functional-element/element-properties.js +0 -55
- package/dist/cjs/functional-element/functional-element.d.ts +0 -44
- package/dist/cjs/functional-element/functional-element.js +0 -7
- package/dist/cjs/functional-element/render-callback.d.ts +0 -21
- package/dist/cjs/functional-element/render-callback.js +0 -24
- package/dist/cjs/index.d.ts +0 -15
- package/dist/cjs/index.js +0 -33
- package/dist/cjs/require-functional-element.d.ts +0 -2
- package/dist/cjs/require-functional-element.js +0 -8
- package/dist/cjs/template-transforms/has-static-tag-name.js +0 -10
- package/dist/cjs/template-transforms/transform-template.js +0 -74
- package/dist/cjs/template-transforms/vir-css/css-transform.js +0 -16
- package/dist/cjs/template-transforms/vir-css/vir-css.d.ts +0 -3
- package/dist/cjs/template-transforms/vir-css/vir-css.js +0 -16
- package/dist/cjs/template-transforms/vir-html/html-transform.js +0 -48
- package/dist/cjs/template-transforms/vir-html/vir-html.d.ts +0 -3
- package/dist/cjs/template-transforms/vir-html/vir-html.js +0 -20
- package/dist/cjs/typed-event/typed-event.js +0 -37
- package/dist/esm/augments/array.d.ts +0 -1
- package/dist/esm/augments/type.d.ts +0 -1
- package/dist/esm/functional-element/define-functional-element.d.ts +0 -4
- package/dist/esm/functional-element/define-functional-element.js +0 -47
- package/dist/esm/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
- package/dist/esm/functional-element/directives/assign-with-clean-up.directive.js +0 -36
- package/dist/esm/functional-element/directives/assign.directive.d.ts +0 -15
- package/dist/esm/functional-element/directives/assign.directive.js +0 -23
- package/dist/esm/functional-element/directives/listen.directive.d.ts +0 -13
- package/dist/esm/functional-element/directives/on-dom-created.directive.d.ts +0 -11
- package/dist/esm/functional-element/directives/on-resize.directive.d.ts +0 -15
- package/dist/esm/functional-element/element-events.d.ts +0 -10
- package/dist/esm/functional-element/element-properties.js +0 -50
- package/dist/esm/functional-element/functional-element.d.ts +0 -44
- package/dist/esm/functional-element/functional-element.js +0 -3
- package/dist/esm/functional-element/render-callback.d.ts +0 -21
- package/dist/esm/index.d.ts +0 -15
- package/dist/esm/index.js +0 -15
- package/dist/esm/require-functional-element.d.ts +0 -2
- package/dist/esm/require-functional-element.js +0 -4
- package/dist/esm/template-transforms/has-static-tag-name.d.ts +0 -4
- package/dist/esm/template-transforms/transform-template.d.ts +0 -16
- package/dist/esm/template-transforms/vir-css/css-transform.d.ts +0 -7
- package/dist/esm/template-transforms/vir-css/vir-css.d.ts +0 -3
- package/dist/esm/template-transforms/vir-html/html-transform.d.ts +0 -3
- package/dist/esm/template-transforms/vir-html/vir-html.d.ts +0 -3
- package/dist/esm/typed-event/typed-event.d.ts +0 -19
- package/dist/types/augments/array.d.ts +0 -1
- package/dist/types/augments/type.d.ts +0 -1
- package/dist/types/functional-element/define-functional-element.d.ts +0 -4
- package/dist/types/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
- package/dist/types/functional-element/directives/assign.directive.d.ts +0 -15
- package/dist/types/functional-element/directives/directive-util.d.ts +0 -15
- package/dist/types/functional-element/directives/on-dom-created.directive.d.ts +0 -11
- package/dist/types/functional-element/directives/on-resize.directive.d.ts +0 -15
- package/dist/types/functional-element/element-events.d.ts +0 -10
- package/dist/types/functional-element/element-properties.d.ts +0 -16
- package/dist/types/functional-element/functional-element.d.ts +0 -44
- package/dist/types/functional-element/render-callback.d.ts +0 -21
- package/dist/types/index.d.ts +0 -15
- package/dist/types/require-functional-element.d.ts +0 -2
- package/dist/types/template-transforms/has-static-tag-name.d.ts +0 -4
- package/dist/types/template-transforms/transform-template.d.ts +0 -16
- package/dist/types/template-transforms/vir-css/css-transform.d.ts +0 -7
- package/dist/types/template-transforms/vir-css/vir-css.d.ts +0 -3
- package/dist/types/template-transforms/vir-html/html-transform.d.ts +0 -3
- package/dist/types/typed-event/typed-event.d.ts +0 -19
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,91 +127,92 @@ 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
|
});
|
|
178
177
|
```
|
|
179
178
|
|
|
180
|
-
|
|
179
|
+
### Assigning to properties (inputs)
|
|
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>(),
|
|
@@ -228,33 +229,33 @@ export const MySimpleWithEventsElement = defineFunctionalElement({
|
|
|
228
229
|
});
|
|
229
230
|
```
|
|
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
|
|
@@ -303,6 +304,87 @@ export const MyElementWithCustomEvents = defineFunctionalElement({
|
|
|
303
304
|
});
|
|
304
305
|
```
|
|
305
306
|
|
|
307
|
+
## Host classes
|
|
308
|
+
|
|
309
|
+
Host classes can be defined and used with type safety. Host classes are used to provide alternative styles for components. They are purely driven by CSS and are thus applied via the `class` HTML attribute.
|
|
310
|
+
|
|
311
|
+
Host classes that are defined with a callback will automatically get applied if that callback returns true after a render is executed. These are executed _after_ `renderCallback` is executed. When a definition is set to `false`, it's left to the element's consumer to apply the host class.
|
|
312
|
+
|
|
313
|
+
Apply host classes in the element's stylesheet by using a callback for the styles property.
|
|
314
|
+
|
|
315
|
+
<!-- example-link: src/readme-examples/host-class-definition.ts -->
|
|
316
|
+
|
|
317
|
+
```TypeScript
|
|
318
|
+
import {css, defineElementNoInputs, html} from 'element-vir';
|
|
319
|
+
|
|
320
|
+
export const MyAppWithHostClasses = defineElementNoInputs({
|
|
321
|
+
tagName: 'my-app-with-host-classes',
|
|
322
|
+
stateInit: {
|
|
323
|
+
myProp: 'hello there',
|
|
324
|
+
},
|
|
325
|
+
hostClasses: {
|
|
326
|
+
/**
|
|
327
|
+
* Setting the value to false means this host class will not ever automatically be applied.
|
|
328
|
+
* It will simply be a static member on the element for manual application in consumers when desired.
|
|
329
|
+
*/
|
|
330
|
+
styleVariationA: false,
|
|
331
|
+
/**
|
|
332
|
+
* This host class will be automatically applied if the given callback evaluated to true
|
|
333
|
+
* after a call to renderCallback.
|
|
334
|
+
*/
|
|
335
|
+
automaticallyAppliedVariation: ({state}) => {
|
|
336
|
+
return state.myProp === 'foo';
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
/**
|
|
340
|
+
* Apply styles to the host classes by using a callback for "styles". The callback's argument
|
|
341
|
+
* contains the host classes defined above in the "hostClasses" property.
|
|
342
|
+
*/
|
|
343
|
+
styles: ({hostClass}) => css`
|
|
344
|
+
${hostClass.automaticallyAppliedVariation} {
|
|
345
|
+
color: blue;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
${hostClass.styleVariationA} {
|
|
349
|
+
color: red;
|
|
350
|
+
}
|
|
351
|
+
`,
|
|
352
|
+
renderCallback: ({state}) => html`
|
|
353
|
+
${state.myProp}
|
|
354
|
+
`,
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## CSS Vars
|
|
359
|
+
|
|
360
|
+
Typed CSS vars are created in a similar way as host classes:
|
|
361
|
+
|
|
362
|
+
<!-- example-link: src/readme-examples/css-vars-definition.ts -->
|
|
363
|
+
|
|
364
|
+
```TypeScript
|
|
365
|
+
import {css, defineElementNoInputs, html} from 'element-vir';
|
|
366
|
+
|
|
367
|
+
export const MyAppWithCssVars = defineElementNoInputs({
|
|
368
|
+
tagName: 'my-app-with-css-vars',
|
|
369
|
+
cssVars: {
|
|
370
|
+
/**
|
|
371
|
+
* The value assigned here ('blue') becomes the fallback value for this CSS var when used
|
|
372
|
+
* via "cssVarValue".
|
|
373
|
+
*/
|
|
374
|
+
myCssVar: 'blue',
|
|
375
|
+
},
|
|
376
|
+
styles: ({cssVarName, cssVarValue}) => css`
|
|
377
|
+
:host {
|
|
378
|
+
/* Set CSS vars (or reference the name directly) via "cssVarName" */
|
|
379
|
+
${cssVarName.myCssVar}: yellow;
|
|
380
|
+
/* Use CSS vars with "cssVarValue". This includes a "var" wrapper and the assigned fallback value (which in this case is 'blue'). */
|
|
381
|
+
color: ${cssVarValue.myCssVar};
|
|
382
|
+
}
|
|
383
|
+
`,
|
|
384
|
+
renderCallback: () => html``,
|
|
385
|
+
});
|
|
386
|
+
```
|
|
387
|
+
|
|
306
388
|
## Directives
|
|
307
389
|
|
|
308
390
|
The following custom [`lit` directives](https://lit.dev/docs/templates/custom-directives/) are contained within this package.
|
|
@@ -316,15 +398,15 @@ This triggers only once when the element it's attached has actually been created
|
|
|
316
398
|
<!-- example-link: src/readme-examples/my-simple-with-on-dom-created.element.ts -->
|
|
317
399
|
|
|
318
400
|
```TypeScript
|
|
319
|
-
import {
|
|
401
|
+
import {defineElementNoInputs, html, onDomCreated} from 'element-vir';
|
|
320
402
|
|
|
321
|
-
export const MySimpleWithOnDomCreatedElement =
|
|
403
|
+
export const MySimpleWithOnDomCreatedElement = defineElementNoInputs({
|
|
322
404
|
tagName: 'my-simple-with-on-dom-created-element',
|
|
323
405
|
renderCallback: () => html`
|
|
324
406
|
<span
|
|
325
407
|
${onDomCreated((element) => {
|
|
326
408
|
// logs a span element
|
|
327
|
-
console.
|
|
409
|
+
console.info(element);
|
|
328
410
|
})}
|
|
329
411
|
>
|
|
330
412
|
Hello there!
|
|
@@ -340,16 +422,16 @@ This directive fulfills a common use case of triggering callbacks when something
|
|
|
340
422
|
<!-- example-link: src/readme-examples/my-simple-with-on-resize.element.ts -->
|
|
341
423
|
|
|
342
424
|
```TypeScript
|
|
343
|
-
import {
|
|
425
|
+
import {defineElementNoInputs, html, onResize} from 'element-vir';
|
|
344
426
|
|
|
345
|
-
export const MySimpleWithOnResizeElement =
|
|
427
|
+
export const MySimpleWithOnResizeElement = defineElementNoInputs({
|
|
346
428
|
tagName: 'my-simple-with-on-dom-created-element',
|
|
347
429
|
renderCallback: () => html`
|
|
348
430
|
<span
|
|
349
431
|
${onResize((entry) => {
|
|
350
432
|
// this will track resizing of this span
|
|
351
433
|
// the entry parameter contains target and contentRect properties
|
|
352
|
-
console.
|
|
434
|
+
console.info(entry);
|
|
353
435
|
})}
|
|
354
436
|
>
|
|
355
437
|
Hello there!
|
|
@@ -373,40 +455,43 @@ This directive is the same as the `assign` directive but it accepts an additiona
|
|
|
373
455
|
<!-- example-link: src/readme-examples/my-app-with-cleanup.element.ts -->
|
|
374
456
|
|
|
375
457
|
```TypeScript
|
|
376
|
-
import {
|
|
377
|
-
import {
|
|
458
|
+
import {assignWithCleanup, defineElementNoInputs, html} from 'element-vir';
|
|
459
|
+
import {MySimpleWithInputsElement} from './my-simple-with-inputs.element';
|
|
378
460
|
|
|
379
|
-
export const
|
|
461
|
+
export const MyAppWithAssignmentCleanupElement = defineElementNoInputs({
|
|
380
462
|
tagName: 'my-app-with-cleanup',
|
|
381
463
|
renderCallback: () => html`
|
|
382
464
|
<h1>My App</h1>
|
|
383
|
-
<${
|
|
465
|
+
<${MySimpleWithInputsElement}
|
|
384
466
|
${assignWithCleanup(
|
|
385
|
-
|
|
386
|
-
|
|
467
|
+
MySimpleWithInputsElement,
|
|
468
|
+
{
|
|
469
|
+
email: 'user@example.com',
|
|
470
|
+
username: 'user',
|
|
471
|
+
},
|
|
387
472
|
(previousValue) => {
|
|
388
473
|
// here would be the cleanup code.
|
|
389
|
-
// In this specific example the value is just a string, so no cleanup is needed
|
|
390
|
-
|
|
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();
|
|
391
477
|
},
|
|
392
478
|
)}
|
|
393
|
-
${assign(MySimpleWithPropsElement.props.currentEmail, 'user@example.com')}
|
|
394
479
|
>
|
|
395
|
-
</${
|
|
480
|
+
</${MySimpleWithInputsElement}>
|
|
396
481
|
`,
|
|
397
482
|
});
|
|
398
483
|
```
|
|
399
484
|
|
|
400
|
-
## Require all child custom elements to be
|
|
485
|
+
## Require all child custom elements to be declarative elements
|
|
401
486
|
|
|
402
|
-
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).
|
|
403
488
|
|
|
404
|
-
<!-- example-link: src/readme-examples/require-
|
|
489
|
+
<!-- example-link: src/readme-examples/require-declarative-element.ts -->
|
|
405
490
|
|
|
406
491
|
```TypeScript
|
|
407
|
-
import {
|
|
492
|
+
import {requireAllCustomElementsToBeDeclarativeElements} from 'element-vir';
|
|
408
493
|
|
|
409
|
-
|
|
494
|
+
requireAllCustomElementsToBeDeclarativeElements();
|
|
410
495
|
```
|
|
411
496
|
|
|
412
497
|
# Dev
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
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;
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CSSResult } from 'lit';
|
|
2
|
+
export declare type CssVarsInitMap<CssVarKeys extends string> = Record<CssVarKeys, string>;
|
|
3
|
+
export declare type CssVarName<TagName extends string> = `--${TagName}-string`;
|
|
4
|
+
export declare type CssVarNameOrValueMap<CssVarKeys extends string> = Record<CssVarKeys, CSSResult>;
|
|
5
|
+
export declare function createCssVarNamesMap<TagName extends string, CssVarKeys extends string>(tagName: TagName, cssVarsInit: CssVarsInitMap<CssVarKeys> | undefined): CssVarNameOrValueMap<CssVarKeys>;
|
|
6
|
+
export declare function createCssVarValuesMap<CssVarKeys extends string>(cssVarInitMap: CssVarsInitMap<CssVarKeys> | undefined, cssVarNamesMap: CssVarNameOrValueMap<CssVarKeys>): CssVarNameOrValueMap<CssVarKeys>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { mapObject } from 'augment-vir';
|
|
2
|
+
import { unsafeCSS } from 'lit';
|
|
3
|
+
import { toHtmlSafeWithTagName } from './tag-name';
|
|
4
|
+
export function createCssVarNamesMap(tagName, cssVarsInit) {
|
|
5
|
+
if (cssVarsInit) {
|
|
6
|
+
return mapObject(cssVarsInit, (key) => {
|
|
7
|
+
return unsafeCSS(`--${toHtmlSafeWithTagName(tagName, String(key))}`);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function createCssVarValuesMap(cssVarInitMap, cssVarNamesMap) {
|
|
15
|
+
if (!cssVarInitMap) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
return mapObject(cssVarInitMap, (key, fallbackValue) => {
|
|
19
|
+
const name = cssVarNamesMap[key];
|
|
20
|
+
return unsafeCSS(`var(${name}, ${fallbackValue})`);
|
|
21
|
+
});
|
|
22
|
+
}
|