element-vir 26.11.2 → 26.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/package.json +12 -12
  2. package/src/declarative-element/declarative-element-init.ts +115 -0
  3. package/src/declarative-element/declarative-element.ts +372 -0
  4. package/src/declarative-element/define-element.ts +515 -0
  5. package/{dist/declarative-element/definition-options.d.ts → src/declarative-element/definition-options.ts} +7 -2
  6. package/src/declarative-element/directives/assign.directive.ts +89 -0
  7. package/{dist/declarative-element/directives/async-prop.js → src/declarative-element/directives/async-prop.ts} +42 -8
  8. package/src/declarative-element/directives/attributes.directive.ts +63 -0
  9. package/src/declarative-element/directives/create-attribute-directive.ts +47 -0
  10. package/src/declarative-element/directives/directive-helpers.ts +67 -0
  11. package/{dist/declarative-element/directives/listen-to-activate.js → src/declarative-element/directives/listen-to-activate.ts} +8 -3
  12. package/src/declarative-element/directives/listen.directive.ts +206 -0
  13. package/src/declarative-element/directives/mutate.directive.ts +78 -0
  14. package/src/declarative-element/directives/on-dom-created.directive.ts +68 -0
  15. package/src/declarative-element/directives/on-dom-rendered.directive.ts +61 -0
  16. package/src/declarative-element/directives/on-intersect.directive.ts +139 -0
  17. package/src/declarative-element/directives/on-resize.directive.ts +142 -0
  18. package/src/declarative-element/directives/render-async.directive.ts +111 -0
  19. package/{dist/declarative-element/directives/render-if.directive.js → src/declarative-element/directives/render-if.directive.ts} +12 -3
  20. package/{dist/declarative-element/directives/test-id.directive.js → src/declarative-element/directives/test-id.directive.ts} +7 -2
  21. package/{dist/declarative-element/has-declarative-element-parent.js → src/declarative-element/has-declarative-element-parent.ts} +7 -4
  22. package/{dist/declarative-element/is-declarative-element-definition.js → src/declarative-element/is-declarative-element-definition.ts} +28 -11
  23. package/{dist/declarative-element/is-declarative-element.js → src/declarative-element/is-declarative-element.ts} +11 -5
  24. package/src/declarative-element/properties/assign-inputs.ts +30 -0
  25. package/src/declarative-element/properties/css-vars.ts +24 -0
  26. package/src/declarative-element/properties/element-events.ts +161 -0
  27. package/src/declarative-element/properties/host-classes.ts +63 -0
  28. package/{dist/declarative-element/properties/property-proxy.js → src/declarative-element/properties/property-proxy.ts} +58 -21
  29. package/src/declarative-element/properties/string-names.ts +83 -0
  30. package/src/declarative-element/properties/styles.ts +112 -0
  31. package/src/declarative-element/render-callback.ts +196 -0
  32. package/src/declarative-element/wrap-define-element.ts +127 -0
  33. package/{dist/index.d.ts → src/index.ts} +2 -0
  34. package/{dist/lit-exports/base-lit-exports.js → src/lit-exports/base-lit-exports.ts} +10 -1
  35. package/{dist/lit-exports/lit-repeat-fix.d.ts → src/lit-exports/lit-repeat-fix.ts} +45 -16
  36. package/{dist/readme-examples/my-app.element.js → src/readme-examples/my-app.element.ts} +5 -4
  37. package/src/readme-examples/my-custom-action.event.ts +3 -0
  38. package/{dist/readme-examples/my-custom-define.js → src/readme-examples/my-custom-define.ts} +9 -4
  39. package/{dist/readme-examples/my-simple.element.js → src/readme-examples/my-simple.element.ts} +4 -3
  40. package/src/readme-examples/my-with-assignment.element.ts +16 -0
  41. package/{dist/readme-examples/my-with-async-prop.element.js → src/readme-examples/my-with-async-prop.element.ts} +24 -16
  42. package/{dist/readme-examples/my-with-cleanup-callback.element.js → src/readme-examples/my-with-cleanup-callback.element.ts} +5 -4
  43. package/{dist/readme-examples/my-with-css-vars.element.js → src/readme-examples/my-with-css-vars.element.ts} +5 -4
  44. package/src/readme-examples/my-with-custom-events.element.ts +23 -0
  45. package/{dist/readme-examples/my-with-event-listening.element.js → src/readme-examples/my-with-event-listening.element.ts} +10 -9
  46. package/src/readme-examples/my-with-events.element.ts +23 -0
  47. package/{dist/readme-examples/my-with-host-class-definition.element.js → src/readme-examples/my-with-host-class-definition.element.ts} +7 -6
  48. package/{dist/readme-examples/my-with-host-class-usage.element.js → src/readme-examples/my-with-host-class-usage.element.ts} +5 -4
  49. package/src/readme-examples/my-with-inputs.element.ts +13 -0
  50. package/{dist/readme-examples/my-with-on-dom-created.element.js → src/readme-examples/my-with-on-dom-created.element.ts} +7 -6
  51. package/src/readme-examples/my-with-on-resize.element.ts +19 -0
  52. package/src/readme-examples/my-with-render-if.element.ts +15 -0
  53. package/{dist/readme-examples/my-with-styles-and-interpolated-selector.element.js → src/readme-examples/my-with-styles-and-interpolated-selector.element.ts} +6 -5
  54. package/{dist/readme-examples/my-with-styles.element.js → src/readme-examples/my-with-styles.element.ts} +5 -4
  55. package/{dist/readme-examples/my-with-update-state.element.js → src/readme-examples/my-with-update-state.element.ts} +8 -7
  56. package/src/readme-examples/require-declarative-element.ts +3 -0
  57. package/{dist/require-declarative-element.js → src/require-declarative-element.ts} +1 -0
  58. package/{dist/template-transforms/minimal-element-definition.d.ts → src/template-transforms/minimal-element-definition.ts} +19 -7
  59. package/src/template-transforms/nested-mapped-templates.ts +157 -0
  60. package/{dist/template-transforms/template-transform-type.d.ts → src/template-transforms/template-transform-type.ts} +3 -1
  61. package/{dist/template-transforms/transform-template.js → src/template-transforms/transform-template.ts} +70 -22
  62. package/src/template-transforms/vir-css/css-transform.ts +30 -0
  63. package/src/template-transforms/vir-css/vir-css.ts +30 -0
  64. package/src/template-transforms/vir-html/html-interpolation.ts +103 -0
  65. package/src/template-transforms/vir-html/html-transform.ts +149 -0
  66. package/{dist/template-transforms/vir-html/tag-name-keys.js → src/template-transforms/vir-html/tag-name-keys.ts} +1 -1
  67. package/{dist/template-transforms/vir-html/vir-html.js → src/template-transforms/vir-html/vir-html.ts} +13 -5
  68. package/src/typed-event/typed-event.ts +90 -0
  69. package/{dist/util/array.js → src/util/array.ts} +18 -5
  70. package/{dist/util/increment.d.ts → src/util/increment.ts} +24 -5
  71. package/{dist/util/lit-template.js → src/util/lit-template.ts} +30 -10
  72. package/src/util/map-async-value.ts +33 -0
  73. package/dist/declarative-element/custom-tag-name.js +0 -1
  74. package/dist/declarative-element/declarative-element-init.d.ts +0 -56
  75. package/dist/declarative-element/declarative-element-init.js +0 -1
  76. package/dist/declarative-element/declarative-element.d.ts +0 -114
  77. package/dist/declarative-element/declarative-element.js +0 -36
  78. package/dist/declarative-element/define-element.d.ts +0 -41
  79. package/dist/declarative-element/define-element.js +0 -248
  80. package/dist/declarative-element/definition-options.js +0 -9
  81. package/dist/declarative-element/directives/assign.directive.d.ts +0 -24
  82. package/dist/declarative-element/directives/assign.directive.js +0 -34
  83. package/dist/declarative-element/directives/async-prop.d.ts +0 -61
  84. package/dist/declarative-element/directives/attributes.directive.d.ts +0 -30
  85. package/dist/declarative-element/directives/attributes.directive.js +0 -35
  86. package/dist/declarative-element/directives/create-attribute-directive.d.ts +0 -28
  87. package/dist/declarative-element/directives/create-attribute-directive.js +0 -41
  88. package/dist/declarative-element/directives/directive-helpers.d.ts +0 -27
  89. package/dist/declarative-element/directives/directive-helpers.js +0 -37
  90. package/dist/declarative-element/directives/listen-to-activate.d.ts +0 -15
  91. package/dist/declarative-element/directives/listen.directive.d.ts +0 -92
  92. package/dist/declarative-element/directives/listen.directive.js +0 -48
  93. package/dist/declarative-element/directives/mutate.directive.d.ts +0 -38
  94. package/dist/declarative-element/directives/mutate.directive.js +0 -45
  95. package/dist/declarative-element/directives/on-dom-created.directive.d.ts +0 -44
  96. package/dist/declarative-element/directives/on-dom-created.directive.js +0 -51
  97. package/dist/declarative-element/directives/on-dom-rendered.directive.d.ts +0 -41
  98. package/dist/declarative-element/directives/on-dom-rendered.directive.js +0 -45
  99. package/dist/declarative-element/directives/on-intersect.directive.d.ts +0 -64
  100. package/dist/declarative-element/directives/on-intersect.directive.js +0 -89
  101. package/dist/declarative-element/directives/on-resize.directive.d.ts +0 -74
  102. package/dist/declarative-element/directives/on-resize.directive.js +0 -106
  103. package/dist/declarative-element/directives/render-async.directive.d.ts +0 -45
  104. package/dist/declarative-element/directives/render-async.directive.js +0 -33
  105. package/dist/declarative-element/directives/render-if.directive.d.ts +0 -32
  106. package/dist/declarative-element/directives/test-id.directive.d.ts +0 -52
  107. package/dist/declarative-element/has-declarative-element-parent.d.ts +0 -1
  108. package/dist/declarative-element/is-declarative-element-definition.d.ts +0 -17
  109. package/dist/declarative-element/is-declarative-element.d.ts +0 -15
  110. package/dist/declarative-element/properties/assign-inputs.d.ts +0 -1
  111. package/dist/declarative-element/properties/assign-inputs.js +0 -25
  112. package/dist/declarative-element/properties/css-vars.d.ts +0 -16
  113. package/dist/declarative-element/properties/css-vars.js +0 -1
  114. package/dist/declarative-element/properties/element-events.d.ts +0 -65
  115. package/dist/declarative-element/properties/element-events.js +0 -62
  116. package/dist/declarative-element/properties/element-properties.js +0 -1
  117. package/dist/declarative-element/properties/host-classes.d.ts +0 -36
  118. package/dist/declarative-element/properties/host-classes.js +0 -16
  119. package/dist/declarative-element/properties/property-proxy.d.ts +0 -22
  120. package/dist/declarative-element/properties/string-names.d.ts +0 -28
  121. package/dist/declarative-element/properties/string-names.js +0 -40
  122. package/dist/declarative-element/properties/styles.d.ts +0 -51
  123. package/dist/declarative-element/properties/styles.js +0 -41
  124. package/dist/declarative-element/properties/tag-name.js +0 -1
  125. package/dist/declarative-element/render-callback.d.ts +0 -56
  126. package/dist/declarative-element/render-callback.js +0 -27
  127. package/dist/declarative-element/wrap-define-element.d.ts +0 -36
  128. package/dist/declarative-element/wrap-define-element.js +0 -25
  129. package/dist/index.js +0 -42
  130. package/dist/lit-exports/all-lit-exports.js +0 -2
  131. package/dist/lit-exports/base-lit-exports.d.ts +0 -25
  132. package/dist/lit-exports/lit-repeat-fix.js +0 -37
  133. package/dist/readme-examples/my-app.element.d.ts +0 -1
  134. package/dist/readme-examples/my-custom-action.event.d.ts +0 -1
  135. package/dist/readme-examples/my-custom-action.event.js +0 -2
  136. package/dist/readme-examples/my-custom-define.d.ts +0 -4
  137. package/dist/readme-examples/my-simple.element.d.ts +0 -1
  138. package/dist/readme-examples/my-with-assignment.element.d.ts +0 -1
  139. package/dist/readme-examples/my-with-assignment.element.js +0 -15
  140. package/dist/readme-examples/my-with-async-prop.element.d.ts +0 -10
  141. package/dist/readme-examples/my-with-cleanup-callback.element.d.ts +0 -3
  142. package/dist/readme-examples/my-with-css-vars.element.d.ts +0 -1
  143. package/dist/readme-examples/my-with-custom-events.element.d.ts +0 -1
  144. package/dist/readme-examples/my-with-custom-events.element.js +0 -22
  145. package/dist/readme-examples/my-with-event-listening.element.d.ts +0 -3
  146. package/dist/readme-examples/my-with-events.element.d.ts +0 -4
  147. package/dist/readme-examples/my-with-events.element.js +0 -20
  148. package/dist/readme-examples/my-with-host-class-definition.element.d.ts +0 -3
  149. package/dist/readme-examples/my-with-host-class-usage.element.d.ts +0 -1
  150. package/dist/readme-examples/my-with-inputs.element.d.ts +0 -4
  151. package/dist/readme-examples/my-with-inputs.element.js +0 -9
  152. package/dist/readme-examples/my-with-on-dom-created.element.d.ts +0 -1
  153. package/dist/readme-examples/my-with-on-resize.element.d.ts +0 -1
  154. package/dist/readme-examples/my-with-on-resize.element.js +0 -18
  155. package/dist/readme-examples/my-with-render-if.element.d.ts +0 -3
  156. package/dist/readme-examples/my-with-render-if.element.js +0 -11
  157. package/dist/readme-examples/my-with-styles-and-interpolated-selector.element.d.ts +0 -1
  158. package/dist/readme-examples/my-with-styles.element.d.ts +0 -1
  159. package/dist/readme-examples/my-with-update-state.element.d.ts +0 -8
  160. package/dist/readme-examples/require-declarative-element.d.ts +0 -1
  161. package/dist/readme-examples/require-declarative-element.js +0 -2
  162. package/dist/require-declarative-element.d.ts +0 -14
  163. package/dist/template-transforms/minimal-element-definition.js +0 -19
  164. package/dist/template-transforms/nested-mapped-templates.d.ts +0 -6
  165. package/dist/template-transforms/nested-mapped-templates.js +0 -96
  166. package/dist/template-transforms/template-transform-type.js +0 -1
  167. package/dist/template-transforms/transform-template.d.ts +0 -14
  168. package/dist/template-transforms/vir-css/css-transform.d.ts +0 -4
  169. package/dist/template-transforms/vir-css/css-transform.js +0 -15
  170. package/dist/template-transforms/vir-css/vir-css.d.ts +0 -12
  171. package/dist/template-transforms/vir-css/vir-css.js +0 -21
  172. package/dist/template-transforms/vir-html/html-interpolation.d.ts +0 -42
  173. package/dist/template-transforms/vir-html/html-interpolation.js +0 -1
  174. package/dist/template-transforms/vir-html/html-transform.d.ts +0 -5
  175. package/dist/template-transforms/vir-html/html-transform.js +0 -96
  176. package/dist/template-transforms/vir-html/tag-name-keys.d.ts +0 -7
  177. package/dist/template-transforms/vir-html/vir-html.d.ts +0 -11
  178. package/dist/typed-event/typed-event.d.ts +0 -55
  179. package/dist/typed-event/typed-event.js +0 -50
  180. package/dist/util/array.d.ts +0 -5
  181. package/dist/util/increment.js +0 -1
  182. package/dist/util/lit-template.d.ts +0 -9
  183. package/dist/util/type.js +0 -1
  184. /package/{dist/declarative-element/custom-tag-name.d.ts → src/declarative-element/custom-tag-name.ts} +0 -0
  185. /package/{dist/declarative-element/properties/element-properties.d.ts → src/declarative-element/properties/element-properties.ts} +0 -0
  186. /package/{dist/declarative-element/properties/tag-name.d.ts → src/declarative-element/properties/tag-name.ts} +0 -0
  187. /package/{dist/lit-exports/all-lit-exports.d.ts → src/lit-exports/all-lit-exports.ts} +0 -0
  188. /package/{dist/util/type.d.ts → src/util/type.ts} +0 -0
@@ -0,0 +1,161 @@
1
+ import {
2
+ type DefinedTypedEvent,
3
+ type DefineEvent,
4
+ defineTypedEvent,
5
+ type TypedEvent,
6
+ } from '../../typed-event/typed-event.js';
7
+ import {type NonEmptyString} from '../../util/type.js';
8
+ import {type CustomElementTagName} from '../custom-tag-name.js';
9
+
10
+ /**
11
+ * Base type for defining element events inside of an element definition.
12
+ *
13
+ * @category Internal
14
+ */
15
+ export type EventsInitMap = Record<string, DefineEvent<any>>;
16
+
17
+ /**
18
+ * Used to define element events, with a type.
19
+ *
20
+ * @category Element Definition
21
+ * @example
22
+ *
23
+ * ```ts
24
+ * import {html, defineElement, defineElementEvent, listen} from 'element-vir';
25
+ *
26
+ * const MyElement = defineElement()({
27
+ * tagName: 'my-element',
28
+ * events: {
29
+ * myOutput: defineElementEvent<number>(),
30
+ * },
31
+ * render({events, dispatch}) {
32
+ * return html`
33
+ * <div
34
+ * ${listen('click', () => {
35
+ * dispatch(new events.myOutput(1));
36
+ * })}
37
+ * >
38
+ * Some div
39
+ * </div>
40
+ * `;
41
+ * },
42
+ * });
43
+ * ```
44
+ */
45
+ export function defineElementEvent<EventDetailGeneric>(): DefineEvent<EventDetailGeneric> {
46
+ return defineTypedEvent<EventDetailGeneric>();
47
+ }
48
+
49
+ /**
50
+ * Extracts the detail type of the given event name from the given event init map.
51
+ *
52
+ * @category Internal
53
+ */
54
+ export type EventInitMapEventDetailExtractor<
55
+ EventTypeNameGeneric extends keyof EventsInitGeneric,
56
+ EventsInitGeneric extends EventsInitMap,
57
+ > = EventsInitGeneric[EventTypeNameGeneric] extends DefineEvent<infer Detail> ? Detail : never;
58
+
59
+ /**
60
+ * Maps the given element tag name and map of event names to their run-time event type strings.
61
+ *
62
+ * @category Internal
63
+ */
64
+ export type EventDescriptorMap<
65
+ TagName extends CustomElementTagName,
66
+ EventsInitGeneric extends EventsInitMap,
67
+ > = {
68
+ [CurrentEventTypeName in keyof EventsInitGeneric]: DefinedTypedEvent<
69
+ CurrentEventTypeName extends string ? `${TagName}-${CurrentEventTypeName}` : never,
70
+ EventInitMapEventDetailExtractor<CurrentEventTypeName, EventsInitGeneric>
71
+ >;
72
+ };
73
+
74
+ /**
75
+ * Extract the event detail type from a {@link TypedEvent}, {@link DefinedTypedEvent}, or
76
+ * `CustomEvent.
77
+ *
78
+ * @category Internal
79
+ */
80
+ export type EventDetail<
81
+ ElementEvent extends TypedEvent<any, any> | DefinedTypedEvent<any, any> | CustomEvent,
82
+ > =
83
+ ElementEvent extends TypedEvent<string, infer Detail>
84
+ ? Detail
85
+ : ElementEvent extends DefinedTypedEvent<any, infer Detail>
86
+ ? Detail
87
+ : ElementEvent extends CustomEvent<infer Detail>
88
+ ? Detail
89
+ : 'TYPE ERROR: failed to extract event detail type';
90
+
91
+ /**
92
+ * Maps an element definition initialization's tag name and event map to a map of ready-to-construct
93
+ * event classes. This also verifies that the input event init map has valid keys.
94
+ *
95
+ * @category Internal
96
+ */
97
+ export function createEventDescriptorMap<
98
+ TagName extends CustomElementTagName,
99
+ EventsInitGeneric extends EventsInitMap,
100
+ >(
101
+ tagName: CustomElementTagName,
102
+ eventsInit: EventsInitGeneric | undefined,
103
+ ): EventDescriptorMap<TagName, EventsInitGeneric> {
104
+ if (!eventsInit) {
105
+ return {} as EventDescriptorMap<TagName, EventsInitGeneric>;
106
+ }
107
+ return (
108
+ Object.keys(eventsInit)
109
+ /** Verify event keys. */
110
+ .filter(
111
+ (
112
+ currentElementEventKey: keyof EventsInitGeneric,
113
+ ): currentElementEventKey is NonEmptyString<keyof EventsInitGeneric> => {
114
+ if (typeof currentElementEventKey !== 'string') {
115
+ throw new TypeError(
116
+ `Expected event key of type string but got type '${typeof currentElementEventKey}' for key ${String(
117
+ currentElementEventKey,
118
+ )}`,
119
+ );
120
+ } else if (currentElementEventKey === '') {
121
+ throw new Error(`Got empty string for events key.`);
122
+ }
123
+ return true;
124
+ },
125
+ )
126
+ .reduce(
127
+ (
128
+ accum: EventDescriptorMap<TagName, EventsInitGeneric>,
129
+ currentElementEventKey: keyof EventsInitGeneric,
130
+ ): EventDescriptorMap<TagName, EventsInitGeneric> => {
131
+ const eventObject: DefinedTypedEvent<
132
+ typeof currentElementEventKey extends string
133
+ ? typeof currentElementEventKey
134
+ : never,
135
+ EventInitMapEventDetailExtractor<
136
+ typeof currentElementEventKey,
137
+ EventsInitGeneric
138
+ >
139
+ > = defineTypedEvent<
140
+ EventInitMapEventDetailExtractor<
141
+ typeof currentElementEventKey,
142
+ EventsInitGeneric
143
+ >
144
+ >()<
145
+ typeof currentElementEventKey extends string
146
+ ? typeof currentElementEventKey
147
+ : never
148
+ >(
149
+ [
150
+ tagName,
151
+ currentElementEventKey,
152
+ ].join('-') as any,
153
+ );
154
+
155
+ accum[currentElementEventKey] = eventObject as any;
156
+ return accum;
157
+ },
158
+ {} as EventDescriptorMap<TagName, EventsInitGeneric>,
159
+ )
160
+ );
161
+ }
@@ -0,0 +1,63 @@
1
+ import {mapObjectValues} from '@augment-vir/common';
2
+ import {type CustomElementTagName} from '../custom-tag-name.js';
3
+ import {type PropertyInitMapBase} from './element-properties.js';
4
+ import {type BaseStringName} from './string-names.js';
5
+ import {type WithTagName} from './tag-name.js';
6
+
7
+ /**
8
+ * Base init map for defining host classes in an element definition.
9
+ *
10
+ * @category Internal
11
+ */
12
+ export type HostClassesInitMap<
13
+ TagName extends CustomElementTagName,
14
+ HostClassKeys extends BaseStringName<TagName>,
15
+ Inputs extends PropertyInitMapBase,
16
+ State extends PropertyInitMapBase,
17
+ > = Record<
18
+ HostClassKeys,
19
+ /**
20
+ * Callback to determine when host class should be enabled (based on current inputs and state),
21
+ * or just undefined to mark that this host class name will only be manually applied.
22
+ */
23
+ ((inputs: {state: Readonly<State>; inputs: Readonly<Inputs>}) => boolean) | false
24
+ >;
25
+
26
+ /**
27
+ * Creates a mapping of host class keys (as defined in an element definition) to their runtime host
28
+ * class names.
29
+ *
30
+ * @category Internal
31
+ */
32
+ export type HostClassNamesMap<TagName extends string, HostClassKeys extends string> = Record<
33
+ HostClassKeys,
34
+ WithTagName<TagName, string>
35
+ >;
36
+
37
+ /**
38
+ * Maps element definition host class definitions to their runtime host class name equivalents.
39
+ *
40
+ * @category Internal
41
+ */
42
+ export function createHostClassNamesMap<
43
+ TagName extends CustomElementTagName,
44
+ HostClassKeys extends BaseStringName<TagName>,
45
+ HostClassesInit extends HostClassesInitMap<
46
+ TagName,
47
+ HostClassKeys,
48
+ /**
49
+ * We can use any here because we don't care what the state or input names are, we just care
50
+ * what the host class names are
51
+ */
52
+ any,
53
+ any
54
+ >,
55
+ >(hostClassesInit?: HostClassesInit): HostClassNamesMap<TagName, HostClassKeys> {
56
+ if (hostClassesInit) {
57
+ return mapObjectValues(hostClassesInit, (key) => {
58
+ return key;
59
+ }) as HostClassNamesMap<TagName, HostClassKeys>;
60
+ } else {
61
+ return {} as HostClassNamesMap<TagName, HostClassKeys>;
62
+ }
63
+ }
@@ -1,54 +1,85 @@
1
- import { isObservableBase } from 'observavir';
2
- import { property } from '../../lit-exports/base-lit-exports.js';
1
+ import {type ObservableListener, isObservableBase} from 'observavir';
2
+ import {property} from '../../lit-exports/base-lit-exports.js';
3
+ import {type DeclarativeElement} from '../declarative-element.js';
4
+ import {type PropertyInitMapBase} from './element-properties.js';
5
+
6
+ /**
7
+ * Used for a map of all observables registered to an element instance.
8
+ *
9
+ * @category Internal
10
+ */
11
+ export type ObservableListenerMap<OriginalPropertyMap extends PropertyInitMapBase> = Partial<
12
+ Record<keyof OriginalPropertyMap, ObservableListener<any> | undefined>
13
+ >;
14
+
3
15
  /**
4
16
  * Binds the given property key as a reactive property on the given element.
5
17
  *
6
18
  * @category Internal
7
19
  */
8
- export function bindReactiveProperty(element, propertyKey) {
20
+ export function bindReactiveProperty(element: HTMLElement, propertyKey: PropertyKey) {
9
21
  if (!(propertyKey in element)) {
10
22
  property()(element, propertyKey);
11
23
  }
12
24
  }
13
- function assertValidPropertyName(propKey, element, elementTagName) {
25
+
26
+ function assertValidPropertyName<PropertyInitGeneric extends PropertyInitMapBase>(
27
+ propKey: any,
28
+ element: DeclarativeElement,
29
+ elementTagName: string,
30
+ ): asserts propKey is keyof PropertyInitGeneric {
14
31
  if (typeof propKey !== 'string' && typeof propKey !== 'number' && typeof propKey !== 'symbol') {
15
- throw new TypeError(`Property name must be a string, got type '${typeof propKey}' from: '${String(propKey)}' for '${elementTagName.toLowerCase()}'`);
32
+ throw new TypeError(
33
+ `Property name must be a string, got type '${typeof propKey}' from: '${String(
34
+ propKey,
35
+ )}' for '${elementTagName.toLowerCase()}'`,
36
+ );
16
37
  }
17
38
  if (!(propKey in element)) {
18
- throw new Error(`Property '${String(propKey)}' does not exist on '${elementTagName.toLowerCase()}'.`);
39
+ throw new Error(
40
+ `Property '${String(propKey)}' does not exist on '${elementTagName.toLowerCase()}'.`,
41
+ );
19
42
  }
20
43
  }
44
+
21
45
  /**
22
46
  * Creates an internal proxy for setting inputs and state properties and then updating them on the
23
47
  * element itself so they will trigger lit's change detection.
24
48
  *
25
49
  * @category Internal
26
50
  */
27
- export function createElementPropertyProxy(element, shouldAlreadyExist) {
51
+ export function createElementPropertyProxy<PropertyInitGeneric extends PropertyInitMapBase>(
52
+ element: DeclarativeElement,
53
+ shouldAlreadyExist: boolean,
54
+ ): PropertyInitGeneric {
28
55
  /**
29
56
  * Lit element updates state and inputs by setting them directly on the element, so we must do
30
57
  * that here. DeclarativeElement's types, however, do not expose this behavior, so we add that
31
58
  * back in here.
32
59
  */
33
- const elementAsProps = element;
34
- function verifyProperty(propertyKey) {
60
+ const elementAsProps = element as DeclarativeElement & PropertyInitGeneric;
61
+
62
+ function verifyProperty(propertyKey: PropertyKey) {
35
63
  if (shouldAlreadyExist) {
36
64
  assertValidPropertyName(propertyKey, element, element.tagName);
37
- }
38
- else {
65
+ } else {
39
66
  bindReactiveProperty(element, propertyKey);
40
67
  }
41
68
  }
42
- function valueGetter(target, propertyKey) {
69
+
70
+ function valueGetter(target: any, propertyKey: keyof PropertyInitGeneric | symbol) {
43
71
  verifyProperty(propertyKey);
72
+
44
73
  return elementAsProps[propertyKey];
45
74
  }
46
- const propsProxy = new Proxy({}, {
75
+
76
+ const propsProxy = new Proxy({} as Record<PropertyKey, unknown>, {
47
77
  get: valueGetter,
48
- set(target, propertyKey, newValue) {
78
+ set(target, propertyKey: keyof PropertyInitGeneric | symbol, newValue) {
49
79
  verifyProperty(propertyKey);
50
80
  const oldValue = elementAsProps[propertyKey];
51
- function setValueOnElement(value) {
81
+
82
+ function setValueOnElement(value: typeof newValue) {
52
83
  /**
53
84
  * We need to at least set the property on target so we can detect it in "ownKeys"
54
85
  * and "getOwnPropertyDescriptor". We don't need duplicates of the values stored in
@@ -57,29 +88,33 @@ export function createElementPropertyProxy(element, shouldAlreadyExist) {
57
88
  target[propertyKey] = value;
58
89
  elementAsProps[propertyKey] = value;
59
90
  }
60
- const existingPropertyListener = element.observablePropertyListenerMap[propertyKey];
91
+
92
+ const existingPropertyListener: ObservableListener<any> | undefined =
93
+ element.observablePropertyListenerMap[propertyKey];
94
+
61
95
  if (oldValue !== newValue && isObservableBase(oldValue) && existingPropertyListener) {
62
96
  /** Stop listening to the old value now that we have a new value */
63
97
  oldValue.removeListener(existingPropertyListener);
64
98
  }
99
+
65
100
  if (isObservableBase(newValue)) {
66
101
  /** If we're using an existing observable property */
67
102
  if (existingPropertyListener) {
68
103
  newValue.listen(false, existingPropertyListener);
69
- }
70
- else {
104
+ } else {
71
105
  function newListener() {
72
106
  element.requestUpdate();
73
107
  }
74
108
  element.observablePropertyListenerMap[propertyKey] = newListener;
75
109
  newValue.listen(false, newListener);
76
110
  }
77
- }
78
- else if (isObservableBase(oldValue)) {
111
+ } else if (isObservableBase(oldValue)) {
79
112
  /** Clear out old listener that is no longer used. */
80
113
  element.observablePropertyListenerMap[propertyKey] = undefined;
81
114
  }
115
+
82
116
  setValueOnElement(newValue);
117
+
83
118
  return true;
84
119
  },
85
120
  ownKeys(target) {
@@ -95,11 +130,13 @@ export function createElementPropertyProxy(element, shouldAlreadyExist) {
95
130
  enumerable: true,
96
131
  };
97
132
  }
133
+
98
134
  return undefined;
99
135
  },
100
136
  has(target, propertyName) {
101
137
  return Reflect.has(target, propertyName);
102
138
  },
103
139
  });
104
- return propsProxy;
140
+
141
+ return propsProxy as PropertyInitGeneric;
105
142
  }
@@ -0,0 +1,83 @@
1
+ import {arrayToObject, type ArrayElement} from '@augment-vir/common';
2
+ import {type CustomElementTagName} from '../custom-tag-name.js';
3
+
4
+ /**
5
+ * Base requirement for all string names with the element tag name prepended.
6
+ *
7
+ * @category Internal
8
+ */
9
+ export type BaseStringName<ElementTagName extends CustomElementTagName> =
10
+ `${ElementTagName}-${string}`;
11
+
12
+ /**
13
+ * Asserts that all the given string names for the given element are valid.
14
+ *
15
+ * @category Internal
16
+ */
17
+ export function assertValidStringNames(
18
+ elementTagName: CustomElementTagName,
19
+ stringNames: Record<BaseStringName<CustomElementTagName>, any>,
20
+ ): void {
21
+ const requiredNameStart = [
22
+ elementTagName,
23
+ '-',
24
+ ].join('');
25
+
26
+ Object.keys(stringNames).forEach((stringName) => {
27
+ if (!stringName.startsWith(requiredNameStart)) {
28
+ throw new Error(
29
+ `Invalid element string name '${stringName}' in '${elementTagName}': element string names must begin with the element's tag name.`,
30
+ );
31
+ }
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Type safe mapping of string names to themself with the element tag name inserted.
37
+ *
38
+ * @category Internal
39
+ */
40
+ export type StringNameMap<
41
+ ElementTagName extends CustomElementTagName,
42
+ NameType extends string,
43
+ StringNames extends ReadonlyArray<string>,
44
+ > = Readonly<{
45
+ [StringName in ArrayElement<StringNames>]: `${ElementTagName}-${NameType}-${StringName}`;
46
+ }>;
47
+
48
+ /**
49
+ * Converts an array of string names into a `StringNameMap`.
50
+ *
51
+ * @category Internal
52
+ */
53
+ export function createStringNameMap<
54
+ ElementTagName extends CustomElementTagName,
55
+ NameType extends string,
56
+ StringNames extends ReadonlyArray<string>,
57
+ >(
58
+ elementTagName: ElementTagName,
59
+ nameType: NameType,
60
+ stringNames: StringNames | undefined,
61
+ ): StringNameMap<ElementTagName, NameType, StringNames> {
62
+ if (!stringNames) {
63
+ return {} as StringNameMap<ElementTagName, NameType, StringNames>;
64
+ }
65
+ const stringNameMap: Record<string, string> = arrayToObject(
66
+ stringNames,
67
+ (stringName) => {
68
+ return {
69
+ key: stringName,
70
+ value: [
71
+ elementTagName,
72
+ nameType,
73
+ stringName,
74
+ ].join('-'),
75
+ };
76
+ },
77
+ {
78
+ useRequired: true,
79
+ },
80
+ );
81
+
82
+ return stringNameMap as StringNameMap<ElementTagName, NameType, StringNames>;
83
+ }
@@ -0,0 +1,112 @@
1
+ import {getObjectTypedKeys, mapObjectValues} from '@augment-vir/common';
2
+ import {type CSSResult, unsafeCSS} from '../../lit-exports/base-lit-exports.js';
3
+ import {type CustomElementTagName} from '../custom-tag-name.js';
4
+ import {type CssVars} from './css-vars.js';
5
+ import {type PropertyInitMapBase} from './element-properties.js';
6
+ import {type HostClassNamesMap, type HostClassesInitMap} from './host-classes.js';
7
+ import {type BaseStringName} from './string-names.js';
8
+
9
+ /**
10
+ * A host class instance to be referenced inside of an element definition's `styles` callback.
11
+ *
12
+ * @category Internal
13
+ */
14
+ export type HostClass = {
15
+ selector: CSSResult;
16
+ name: CSSResult;
17
+ };
18
+
19
+ /**
20
+ * Input type for an element definition's `styles` callback.
21
+ *
22
+ * @category Internal
23
+ */
24
+ export type StylesCallbackInput<
25
+ TagName extends CustomElementTagName,
26
+ HostClassKeys extends BaseStringName<TagName>,
27
+ CssVarKeys extends BaseStringName<TagName>,
28
+ > = {
29
+ hostClasses: Record<HostClassKeys, HostClass>;
30
+ cssVars: Readonly<CssVars<TagName, CssVarKeys>>;
31
+ };
32
+
33
+ /**
34
+ * The type for an element definition's `styles` callback.
35
+ *
36
+ * @category Internal
37
+ */
38
+ export type StylesCallback<
39
+ TagName extends CustomElementTagName,
40
+ HostClassKeys extends BaseStringName<TagName>,
41
+ CssVarKeys extends BaseStringName<TagName>,
42
+ > = (input: StylesCallbackInput<TagName, HostClassKeys, CssVarKeys>) => CSSResult;
43
+
44
+ /**
45
+ * Creates the input for an element definition's `styles` callback.
46
+ *
47
+ * @category Internal
48
+ */
49
+ export function createStylesCallbackInput<
50
+ TagName extends CustomElementTagName,
51
+ HostClassKeys extends BaseStringName<TagName>,
52
+ CssVarKeys extends BaseStringName<TagName>,
53
+ >({
54
+ hostClassNames,
55
+ cssVars,
56
+ }: {
57
+ hostClassNames: HostClassNamesMap<TagName, HostClassKeys>;
58
+ cssVars: Readonly<CssVars<TagName, CssVarKeys>>;
59
+ }): StylesCallbackInput<TagName, HostClassKeys, CssVarKeys> {
60
+ return {
61
+ hostClasses: mapObjectValues(hostClassNames, (key, name): HostClass => {
62
+ return {
63
+ name: unsafeCSS(name),
64
+ selector: unsafeCSS(`:host(.${name})`),
65
+ };
66
+ }),
67
+ cssVars,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Used inside of an element instance to apply host classes on each render.
73
+ *
74
+ * @category Internal
75
+ */
76
+ export function applyHostClasses<
77
+ TagName extends CustomElementTagName,
78
+ Inputs extends PropertyInitMapBase,
79
+ State extends PropertyInitMapBase,
80
+ HostClassKeys extends BaseStringName<TagName>,
81
+ >({
82
+ host,
83
+ hostClassesInit,
84
+ hostClassNames,
85
+ state,
86
+ inputs,
87
+ }: {
88
+ host: HTMLElement;
89
+ hostClassesInit:
90
+ | Readonly<HostClassesInitMap<TagName, HostClassKeys, Inputs, State>>
91
+ | undefined;
92
+ hostClassNames: HostClassNamesMap<string, HostClassKeys>;
93
+ state: Readonly<State>;
94
+ inputs: Readonly<Inputs>;
95
+ }): void {
96
+ if (!hostClassesInit) {
97
+ return;
98
+ }
99
+ getObjectTypedKeys(hostClassesInit).forEach((hostClassKey) => {
100
+ const maybeCallback = hostClassesInit[hostClassKey];
101
+ const hostClassName = hostClassNames[hostClassKey];
102
+
103
+ if (typeof maybeCallback === 'function') {
104
+ const shouldApplyHostClass = maybeCallback({state, inputs});
105
+ if (shouldApplyHostClass) {
106
+ host.classList.add(hostClassName);
107
+ } else {
108
+ host.classList.remove(hostClassName);
109
+ }
110
+ }
111
+ });
112
+ }