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.
Files changed (152) hide show
  1. package/README.md +171 -86
  2. package/dist/{cjs/augments → augments}/array.d.ts +0 -0
  3. package/dist/{esm/augments → augments}/array.js +0 -0
  4. package/dist/augments/testing.d.ts +15 -0
  5. package/dist/augments/testing.js +76 -0
  6. package/dist/augments/type.d.ts +8 -0
  7. package/dist/augments/type.js +13 -0
  8. package/dist/declarative-element/css-vars.d.ts +6 -0
  9. package/dist/declarative-element/css-vars.js +22 -0
  10. package/dist/declarative-element/declarative-element-init.d.ts +33 -0
  11. package/dist/{esm/augments/type.js → declarative-element/declarative-element-init.js} +0 -0
  12. package/dist/declarative-element/declarative-element.d.ts +44 -0
  13. package/dist/declarative-element/declarative-element.js +18 -0
  14. package/dist/declarative-element/define-element-no-inputs.d.ts +5 -0
  15. package/dist/declarative-element/define-element-no-inputs.js +117 -0
  16. package/dist/declarative-element/define-element.d.ts +5 -0
  17. package/dist/declarative-element/define-element.js +13 -0
  18. package/dist/declarative-element/definition-options.d.ts +5 -0
  19. package/dist/declarative-element/definition-options.js +4 -0
  20. package/dist/declarative-element/directives/assign-with-clean-up.directive.d.ts +23 -0
  21. package/dist/declarative-element/directives/assign-with-clean-up.directive.js +43 -0
  22. package/dist/declarative-element/directives/assign.directive.d.ts +12 -0
  23. package/dist/declarative-element/directives/assign.directive.js +35 -0
  24. package/dist/{esm/functional-element/directives/directive-util.d.ts → declarative-element/directives/directive-helpers.d.ts} +2 -3
  25. package/dist/{esm/functional-element/directives/directive-util.js → declarative-element/directives/directive-helpers.js} +4 -4
  26. package/dist/{types/functional-element → declarative-element}/directives/listen.directive.d.ts +2 -2
  27. package/dist/{esm/functional-element → declarative-element}/directives/listen.directive.js +1 -1
  28. package/dist/{cjs/functional-element → declarative-element}/directives/on-dom-created.directive.d.ts +0 -0
  29. package/dist/{esm/functional-element → declarative-element}/directives/on-dom-created.directive.js +1 -1
  30. package/dist/{cjs/functional-element → declarative-element}/directives/on-resize.directive.d.ts +0 -0
  31. package/dist/{esm/functional-element → declarative-element}/directives/on-resize.directive.js +1 -1
  32. package/dist/{cjs/functional-element → declarative-element}/element-events.d.ts +0 -0
  33. package/dist/{esm/functional-element → declarative-element}/element-events.js +1 -1
  34. package/dist/{esm/functional-element → declarative-element}/element-properties.d.ts +3 -3
  35. package/dist/declarative-element/element-properties.js +53 -0
  36. package/dist/declarative-element/has-declarative-element-parent.d.ts +1 -0
  37. package/dist/declarative-element/has-declarative-element-parent.js +16 -0
  38. package/dist/declarative-element/host-classes.d.ts +21 -0
  39. package/dist/declarative-element/host-classes.js +12 -0
  40. package/dist/declarative-element/render-callback.d.ts +22 -0
  41. package/dist/{esm/functional-element → declarative-element}/render-callback.js +4 -3
  42. package/dist/declarative-element/styles.d.ts +22 -0
  43. package/dist/declarative-element/styles.js +29 -0
  44. package/dist/declarative-element/tag-name.d.ts +2 -0
  45. package/dist/declarative-element/tag-name.js +4 -0
  46. package/dist/declarative-element-marker-symbol.d.ts +1 -0
  47. package/dist/declarative-element-marker-symbol.js +1 -0
  48. package/dist/index.d.ts +17 -0
  49. package/dist/index.js +16 -0
  50. package/dist/require-declarative-element.d.ts +2 -0
  51. package/dist/require-declarative-element.js +4 -0
  52. package/dist/{cjs/template-transforms → template-transforms}/has-static-tag-name.d.ts +0 -0
  53. package/dist/{esm/template-transforms → template-transforms}/has-static-tag-name.js +0 -0
  54. package/dist/template-transforms/nested-mapped-templates.d.ts +6 -0
  55. package/dist/template-transforms/nested-mapped-templates.js +96 -0
  56. package/dist/{cjs/template-transforms → template-transforms}/transform-template.d.ts +0 -0
  57. package/dist/{esm/template-transforms → template-transforms}/transform-template.js +21 -2
  58. package/dist/{cjs/template-transforms → template-transforms}/vir-css/css-transform.d.ts +2 -2
  59. package/dist/{esm/template-transforms → template-transforms}/vir-css/css-transform.js +0 -0
  60. package/dist/template-transforms/vir-css/vir-css.d.ts +3 -0
  61. package/dist/{esm/template-transforms → template-transforms}/vir-css/vir-css.js +1 -1
  62. package/dist/{cjs/template-transforms → template-transforms}/vir-html/html-transform.d.ts +0 -0
  63. package/dist/{esm/template-transforms → template-transforms}/vir-html/html-transform.js +3 -3
  64. package/dist/{types/template-transforms → template-transforms}/vir-html/vir-html.d.ts +1 -1
  65. package/dist/{esm/template-transforms → template-transforms}/vir-html/vir-html.js +1 -1
  66. package/dist/{cjs/typed-event → typed-event}/typed-event.d.ts +0 -0
  67. package/dist/{esm/typed-event → typed-event}/typed-event.js +0 -0
  68. package/index.html +14 -0
  69. package/package.json +17 -18
  70. package/public/index.css +7 -0
  71. package/dist/cjs/augments/array.js +0 -7
  72. package/dist/cjs/augments/type.d.ts +0 -1
  73. package/dist/cjs/augments/type.js +0 -2
  74. package/dist/cjs/functional-element/define-functional-element.d.ts +0 -4
  75. package/dist/cjs/functional-element/define-functional-element.js +0 -51
  76. package/dist/cjs/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
  77. package/dist/cjs/functional-element/directives/assign-with-clean-up.directive.js +0 -40
  78. package/dist/cjs/functional-element/directives/assign.directive.d.ts +0 -15
  79. package/dist/cjs/functional-element/directives/assign.directive.js +0 -27
  80. package/dist/cjs/functional-element/directives/directive-util.d.ts +0 -15
  81. package/dist/cjs/functional-element/directives/directive-util.js +0 -27
  82. package/dist/cjs/functional-element/directives/listen.directive.d.ts +0 -13
  83. package/dist/cjs/functional-element/directives/listen.directive.js +0 -51
  84. package/dist/cjs/functional-element/directives/on-dom-created.directive.js +0 -26
  85. package/dist/cjs/functional-element/directives/on-resize.directive.js +0 -39
  86. package/dist/cjs/functional-element/element-events.js +0 -29
  87. package/dist/cjs/functional-element/element-properties.d.ts +0 -16
  88. package/dist/cjs/functional-element/element-properties.js +0 -55
  89. package/dist/cjs/functional-element/functional-element.d.ts +0 -44
  90. package/dist/cjs/functional-element/functional-element.js +0 -7
  91. package/dist/cjs/functional-element/render-callback.d.ts +0 -21
  92. package/dist/cjs/functional-element/render-callback.js +0 -24
  93. package/dist/cjs/index.d.ts +0 -15
  94. package/dist/cjs/index.js +0 -33
  95. package/dist/cjs/require-functional-element.d.ts +0 -2
  96. package/dist/cjs/require-functional-element.js +0 -8
  97. package/dist/cjs/template-transforms/has-static-tag-name.js +0 -10
  98. package/dist/cjs/template-transforms/transform-template.js +0 -74
  99. package/dist/cjs/template-transforms/vir-css/css-transform.js +0 -16
  100. package/dist/cjs/template-transforms/vir-css/vir-css.d.ts +0 -3
  101. package/dist/cjs/template-transforms/vir-css/vir-css.js +0 -16
  102. package/dist/cjs/template-transforms/vir-html/html-transform.js +0 -48
  103. package/dist/cjs/template-transforms/vir-html/vir-html.d.ts +0 -3
  104. package/dist/cjs/template-transforms/vir-html/vir-html.js +0 -20
  105. package/dist/cjs/typed-event/typed-event.js +0 -37
  106. package/dist/esm/augments/array.d.ts +0 -1
  107. package/dist/esm/augments/type.d.ts +0 -1
  108. package/dist/esm/functional-element/define-functional-element.d.ts +0 -4
  109. package/dist/esm/functional-element/define-functional-element.js +0 -47
  110. package/dist/esm/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
  111. package/dist/esm/functional-element/directives/assign-with-clean-up.directive.js +0 -36
  112. package/dist/esm/functional-element/directives/assign.directive.d.ts +0 -15
  113. package/dist/esm/functional-element/directives/assign.directive.js +0 -23
  114. package/dist/esm/functional-element/directives/listen.directive.d.ts +0 -13
  115. package/dist/esm/functional-element/directives/on-dom-created.directive.d.ts +0 -11
  116. package/dist/esm/functional-element/directives/on-resize.directive.d.ts +0 -15
  117. package/dist/esm/functional-element/element-events.d.ts +0 -10
  118. package/dist/esm/functional-element/element-properties.js +0 -50
  119. package/dist/esm/functional-element/functional-element.d.ts +0 -44
  120. package/dist/esm/functional-element/functional-element.js +0 -3
  121. package/dist/esm/functional-element/render-callback.d.ts +0 -21
  122. package/dist/esm/index.d.ts +0 -15
  123. package/dist/esm/index.js +0 -15
  124. package/dist/esm/require-functional-element.d.ts +0 -2
  125. package/dist/esm/require-functional-element.js +0 -4
  126. package/dist/esm/template-transforms/has-static-tag-name.d.ts +0 -4
  127. package/dist/esm/template-transforms/transform-template.d.ts +0 -16
  128. package/dist/esm/template-transforms/vir-css/css-transform.d.ts +0 -7
  129. package/dist/esm/template-transforms/vir-css/vir-css.d.ts +0 -3
  130. package/dist/esm/template-transforms/vir-html/html-transform.d.ts +0 -3
  131. package/dist/esm/template-transforms/vir-html/vir-html.d.ts +0 -3
  132. package/dist/esm/typed-event/typed-event.d.ts +0 -19
  133. package/dist/types/augments/array.d.ts +0 -1
  134. package/dist/types/augments/type.d.ts +0 -1
  135. package/dist/types/functional-element/define-functional-element.d.ts +0 -4
  136. package/dist/types/functional-element/directives/assign-with-clean-up.directive.d.ts +0 -19
  137. package/dist/types/functional-element/directives/assign.directive.d.ts +0 -15
  138. package/dist/types/functional-element/directives/directive-util.d.ts +0 -15
  139. package/dist/types/functional-element/directives/on-dom-created.directive.d.ts +0 -11
  140. package/dist/types/functional-element/directives/on-resize.directive.d.ts +0 -15
  141. package/dist/types/functional-element/element-events.d.ts +0 -10
  142. package/dist/types/functional-element/element-properties.d.ts +0 -16
  143. package/dist/types/functional-element/functional-element.d.ts +0 -44
  144. package/dist/types/functional-element/render-callback.d.ts +0 -21
  145. package/dist/types/index.d.ts +0 -15
  146. package/dist/types/require-functional-element.d.ts +0 -2
  147. package/dist/types/template-transforms/has-static-tag-name.d.ts +0 -4
  148. package/dist/types/template-transforms/transform-template.d.ts +0 -16
  149. package/dist/types/template-transforms/vir-css/css-transform.d.ts +0 -7
  150. package/dist/types/template-transforms/vir-css/vir-css.d.ts +0 -3
  151. package/dist/types/template-transforms/vir-html/html-transform.d.ts +0 -3
  152. 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. Functional. Type safe. Web components without compromise.
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 functional-programming style component definition.
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 [`defineFunctionalElement` function](https://github.com/electrovir/element-vir/blob/main/src/functional-element/define-functional-element.ts#L25-L30). See the [`FunctionalElementInit` type](https://github.com/electrovir/element-vir/blob/main/src/functional-element/functional-element-init.ts#L7-L20) for that function's inputs. These inputs are also described below with examples.
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 `defineFunctionalElement` to define your element. Tt must be given an object with at least `tagName` and `renderCallback` properties (the types enforce this). Here is a bare-minimum example custom element:
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 {defineFunctionalElement, html} from 'element-vir';
43
+ import {defineElementNoInputs, html} from 'element-vir';
44
44
 
45
- export const MySimpleElement = defineFunctionalElement({
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 functional elements (like `my-simple-element` above), they must be interpolated into HTML templates like so:
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 {defineFunctionalElement, html} from 'element-vir';
62
+ import {defineElementNoInputs, html} from 'element-vir';
63
63
  import {MySimpleElement} from './my-simple.element';
64
64
 
65
- export const MyAppElement = defineFunctionalElement({
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 functional element (similar to [how they are defined in `lit`](https://lit.dev/docs/components/styles/)):
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, defineFunctionalElement, html} from 'element-vir';
85
+ import {css, defineElementNoInputs, html} from 'element-vir';
86
86
 
87
- export const MySimpleWithStylesElement = defineFunctionalElement({
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
- Functional 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:
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, defineFunctionalElement, html} from 'element-vir';
114
+ import {css, defineElementNoInputs, html} from 'element-vir';
115
115
  import {MySimpleElement} from './my-simple.element';
116
116
 
117
- export const MySimpleWithStylesAndInterpolatedSelectorElement = defineFunctionalElement({
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 properties (inputs)
130
+ ## Defining and using Inputs
131
131
 
132
- Define element properties with `props` when making a functional element. Each property must be given a default value. If you wish to leave the property's default value as `undefined`, give it a type as well (shown below with `as string | undefined`) so you can assign a defined value of that type to it later.
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 a custom element's properties, grab `props` from `renderCallback`'s parameters and interpolate it into your HTML template:
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-props.element.ts -->
136
+ <!-- example-link: src/readme-examples/my-simple-with-inputs.element.ts -->
137
137
 
138
138
  ```TypeScript
139
- import {defineFunctionalElement, html} from 'element-vir';
140
-
141
- export const MySimpleWithPropsElement = defineFunctionalElement({
142
- tagName: 'my-simple-element-with-props',
143
- props: {
144
- currentUsername: 'dev',
145
- currentEmail: undefined as string | undefined,
146
- },
147
- renderCallback: ({props}) => html`
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
- ## Updating properties
152
+ ## Defining internal state
154
153
 
155
- Grab `setProps` from `renderCallback`'s parameters to update the values in `props`. This causes a re-render. (Note that this example also uses the `listen` directive to respond to click events.)
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-set-props.element.ts -->
156
+ <!-- example-link: src/readme-examples/my-simple-with-update-state.element.ts -->
158
157
 
159
158
  ```TypeScript
160
- import {defineFunctionalElement, html, listen} from 'element-vir';
159
+ import {defineElementNoInputs, html, listen} from 'element-vir';
161
160
 
162
- export const MySimpleWithPropsElement = defineFunctionalElement({
163
- tagName: 'my-simple-element-with-props',
164
- props: {
165
- currentUsername: 'dev',
166
- currentEmail: undefined as string | undefined,
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: ({props, setProps}) => html`
167
+ renderCallback: ({state, updateState}) => html`
169
168
  <span
170
169
  ${listen('click', () => {
171
- setProps({currentUsername: 'new name!'});
170
+ updateState({username: 'new name!'});
172
171
  })}
173
172
  >
174
- Hello there ${props.currentUsername}!
173
+ Hello there ${state.username}!
175
174
  </span>
176
175
  `,
177
176
  });
178
177
  ```
179
178
 
180
- ## Assigning to properties (inputs)
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-props.element.ts -->
183
+ <!-- example-link: src/readme-examples/my-app-with-assignment.element.ts -->
185
184
 
186
185
  ```TypeScript
187
- import {assign, defineFunctionalElement, html} from 'element-vir';
188
- import {MySimpleWithPropsElement} from './my-simple-with-props.element';
186
+ import {assign, defineElementNoInputs, html} from 'element-vir';
187
+ import {MySimpleWithInputsElement} from './my-simple-with-inputs.element';
189
188
 
190
- export const MyAppWithPropsElement = defineFunctionalElement({
191
- tagName: 'my-app-with-props-element',
189
+ export const MyAppWithAssignmentElement = defineElementNoInputs({
190
+ tagName: 'my-app-with-assignment-element',
192
191
  renderCallback: () => html`
193
192
  <h1>My App</h1>
194
- <${MySimpleWithPropsElement}
195
- ${assign(MySimpleWithPropsElement.props.currentUsername, 'user')}
196
- ${assign(MySimpleWithPropsElement.props.currentEmail, 'user@example.com')}
193
+ <${MySimpleWithInputsElement}
194
+ ${assign(MySimpleWithInputsElement, {
195
+ email: 'user@example.com',
196
+ username: 'user',
197
+ })}
197
198
  >
198
- </${MySimpleWithPropsElement}>
199
+ </${MySimpleWithInputsElement}>
199
200
  `,
200
201
  });
201
202
  ```
202
203
 
203
204
  ## Element events (outputs)
204
205
 
205
- Define events with `events` when making a functional 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
+ 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, defineFunctionalElement, html, listen} from 'element-vir';
213
+ import {defineElementEvent, defineElementNoInputs, html, listen} from 'element-vir';
213
214
 
214
- export const MySimpleWithEventsElement = defineFunctionalElement({
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
- ## Listening to typed events (outputs)
232
+ ### Listening to typed events (outputs)
232
233
 
233
- Use the `listen` directive to listen to typed events emitted by your custom functional elements:
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 {defineFunctionalElement, html, listen} from 'element-vir';
239
+ import {defineElementNoInputs, html, listen} from 'element-vir';
239
240
  import {MySimpleWithEventsElement} from './my-simple-with-events.element';
240
241
 
241
- export const MyAppWithEventsElement = defineFunctionalElement({
242
+ export const MyAppWithEventsElement = defineElementNoInputs({
242
243
  tagName: 'my-app-with-events-element',
243
- props: {
244
+ stateInit: {
244
245
  myNumber: -1,
245
246
  },
246
- renderCallback: ({props, setProps}) => html`
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
- setProps({myNumber: event.detail});
254
+ updateState({myNumber: event.detail});
254
255
  })}
255
256
  >
256
257
  </${MySimpleWithEventsElement}>
257
- <span>${props.myNumber}</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 {defineFunctionalElement, html, listen} from 'element-vir';
286
+ import {defineElementNoInputs, html, listen} from 'element-vir';
286
287
  import {MyCustomEvent} from './custom-event-no-element';
287
288
 
288
- export const MyElementWithCustomEvents = defineFunctionalElement({
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.log(`Got a number! ${event.detail}`);
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 {defineFunctionalElement, html, onDomCreated} from 'element-vir';
401
+ import {defineElementNoInputs, html, onDomCreated} from 'element-vir';
320
402
 
321
- export const MySimpleWithOnDomCreatedElement = defineFunctionalElement({
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.log(element);
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 {defineFunctionalElement, html, onResize} from 'element-vir';
425
+ import {defineElementNoInputs, html, onResize} from 'element-vir';
344
426
 
345
- export const MySimpleWithOnResizeElement = defineFunctionalElement({
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.log(entry);
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 {assign, assignWithCleanup, defineFunctionalElement, html} from 'element-vir';
377
- import {MySimpleWithPropsElement} from './my-simple-with-props.element';
458
+ import {assignWithCleanup, defineElementNoInputs, html} from 'element-vir';
459
+ import {MySimpleWithInputsElement} from './my-simple-with-inputs.element';
378
460
 
379
- export const MyAppWithPropsElement = defineFunctionalElement({
461
+ export const MyAppWithAssignmentCleanupElement = defineElementNoInputs({
380
462
  tagName: 'my-app-with-cleanup',
381
463
  renderCallback: () => html`
382
464
  <h1>My App</h1>
383
- <${MySimpleWithPropsElement}
465
+ <${MySimpleWithInputsElement}
384
466
  ${assignWithCleanup(
385
- MySimpleWithPropsElement.props.currentUsername,
386
- 'user',
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
- previousValue.trim();
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
- </${MySimpleWithPropsElement}>
480
+ </${MySimpleWithInputsElement}>
396
481
  `,
397
482
  });
398
483
  ```
399
484
 
400
- ## Require all child custom elements to be functional elements
485
+ ## Require all child custom elements to be declarative elements
401
486
 
402
- To require all child elements to be functional elements defined by this package, call `requireAllCustomElementsToBeFunctionalElement` 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).
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-functional-element.ts -->
489
+ <!-- example-link: src/readme-examples/require-declarative-element.ts -->
405
490
 
406
491
  ```TypeScript
407
- import {requireAllCustomElementsToBeFunctionalElement} from 'element-vir';
492
+ import {requireAllCustomElementsToBeDeclarativeElements} from 'element-vir';
408
493
 
409
- requireAllCustomElementsToBeFunctionalElement();
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
+ }