@thomas-siegfried/tapout 0.0.1 → 0.0.3

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 (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1207 -1205
  3. package/decorator-config.md +220 -0
  4. package/dist/wireParams.d.ts.map +1 -1
  5. package/dist/wireParams.js +27 -4
  6. package/dist/wireParams.js.map +1 -1
  7. package/llms.txt +360 -0
  8. package/package.json +57 -55
  9. package/src/applyBindings.ts +372 -372
  10. package/src/arrayToDomMapping.ts +300 -300
  11. package/src/attributeInterpolationMarkup.ts +91 -91
  12. package/src/bindingContext.ts +207 -207
  13. package/src/bindingEvent.ts +198 -198
  14. package/src/bindingProvider.ts +260 -260
  15. package/src/bindings.ts +963 -963
  16. package/src/compareArrays.ts +122 -122
  17. package/src/componentBinding.ts +318 -318
  18. package/src/componentDecorator.ts +62 -62
  19. package/src/components.ts +367 -367
  20. package/src/computed.ts +439 -439
  21. package/src/configure.ts +52 -52
  22. package/src/controlFlowBindings.ts +206 -206
  23. package/src/core.ts +60 -60
  24. package/src/decorators.ts +407 -407
  25. package/src/dependencyDetection.ts +76 -76
  26. package/src/disposable.ts +36 -36
  27. package/src/domData.ts +42 -42
  28. package/src/domNodeDisposal.ts +94 -94
  29. package/src/effects.ts +29 -29
  30. package/src/event.ts +173 -173
  31. package/src/expressionRewriting.ts +219 -219
  32. package/src/extenders.ts +102 -102
  33. package/src/filters.ts +91 -91
  34. package/src/index.ts +150 -150
  35. package/src/interpolationMarkup.ts +130 -130
  36. package/src/memoization.ts +71 -71
  37. package/src/namespacedBindings.ts +132 -132
  38. package/src/observable.ts +48 -48
  39. package/src/observableArray.ts +397 -397
  40. package/src/options.ts +25 -25
  41. package/src/selectExtensions.ts +68 -68
  42. package/src/slotBinding.ts +84 -84
  43. package/src/subscribable.ts +266 -266
  44. package/src/tasks.ts +79 -79
  45. package/src/templateEngine.ts +108 -108
  46. package/src/templateRendering.ts +399 -399
  47. package/src/templateRewriting.ts +94 -94
  48. package/src/templateSources.ts +134 -134
  49. package/src/utils.ts +123 -123
  50. package/src/utilsDom.ts +87 -87
  51. package/src/virtualElements.ts +153 -153
  52. package/src/wireParams.ts +69 -49
@@ -1,318 +1,318 @@
1
- import { Computed } from './computed.js';
2
- import { ignore } from './dependencyDetection.js';
3
- import { addDisposeCallback } from './domNodeDisposal.js';
4
- import { bindingEvent } from './bindingEvent.js';
5
- import { BindingProvider, bindingHandlers, setCustomElementHooks, addNodePreprocessor } from './bindingProvider.js';
6
- import type { BindingHandler } from './bindingProvider.js';
7
- import { BindingContext } from './bindingContext.js';
8
- import { applyBindingsToDescendants } from './applyBindings.js';
9
- import {
10
- virtualChildNodes,
11
- virtualEmptyNode,
12
- virtualSetChildren,
13
- allowedVirtualElementBindings,
14
- } from './virtualElements.js';
15
- import { unwrapObservable } from './utils.js';
16
- import { cloneNodes } from './utilsDom.js';
17
- import { isReadableSubscribable } from './subscribable.js';
18
- import { Observable } from './observable.js';
19
- import { parseObjectLiteral } from './expressionRewriting.js';
20
- import { getObservable } from './decorators.js';
21
- import { wireParams } from './wireParams.js';
22
- import { options } from './options.js';
23
- import * as components from './components.js';
24
- import type { ComponentDefinition, ComponentInfo } from './components.js';
25
-
26
- let componentLoadingOperationUniqueId = 0;
27
-
28
- function cloneTemplateIntoElement(
29
- componentName: string,
30
- componentDefinition: ComponentDefinition,
31
- element: Node,
32
- ): void {
33
- const template = componentDefinition.template;
34
- if (!template) {
35
- throw new Error("Component '" + componentName + "' has no template");
36
- }
37
- const clonedNodesArray = cloneNodes(template);
38
- virtualSetChildren(element, clonedNodesArray);
39
- }
40
-
41
- function createViewModel(
42
- componentDefinition: ComponentDefinition,
43
- componentParams: unknown,
44
- componentInfo: ComponentInfo,
45
- ): unknown {
46
- const factory = componentDefinition.createViewModel;
47
- return factory
48
- ? factory.call(componentDefinition, componentParams, componentInfo)
49
- : componentParams;
50
- }
51
-
52
- const componentHandler: BindingHandler = {
53
- init(element, valueAccessor, _allBindings, _viewModel, bindingContext) {
54
- let currentViewModel: unknown;
55
- let currentLoadingOperationId: number | null;
56
- let afterRenderSub: { dispose(): void } | null = null;
57
-
58
- function disposeAssociatedComponentViewModel() {
59
- const vm = currentViewModel as { dispose?: () => void } | null;
60
- if (typeof vm?.dispose === 'function') {
61
- vm.dispose();
62
- }
63
- if (afterRenderSub) {
64
- afterRenderSub.dispose();
65
- }
66
- afterRenderSub = null;
67
- currentViewModel = null;
68
- currentLoadingOperationId = null;
69
- }
70
-
71
- const originalChildNodes = Array.from(virtualChildNodes(element));
72
-
73
- virtualEmptyNode(element);
74
- addDisposeCallback(element, disposeAssociatedComponentViewModel);
75
-
76
- const computed = new Computed(() => {
77
- const value = unwrapObservable(valueAccessor());
78
- let componentName: string;
79
- let componentParams: unknown;
80
-
81
- if (typeof value === 'string') {
82
- componentName = value;
83
- } else {
84
- const obj = value as { name: unknown; params?: unknown };
85
- componentName = unwrapObservable(obj.name) as string;
86
- componentParams = unwrapObservable(obj.params);
87
- }
88
-
89
- if (!componentName) {
90
- throw new Error('No component name specified');
91
- }
92
-
93
- const asyncContext = bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);
94
-
95
- const loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
96
-
97
- components.get(componentName, (componentDefinition) => {
98
- if (currentLoadingOperationId !== loadingOperationId) {
99
- return;
100
- }
101
-
102
- disposeAssociatedComponentViewModel();
103
-
104
- if (!componentDefinition) {
105
- throw new Error("Unknown component '" + componentName + "'");
106
- }
107
-
108
- cloneTemplateIntoElement(componentName, componentDefinition, element);
109
-
110
- const componentInfo: ComponentInfo = {
111
- element,
112
- templateNodes: originalChildNodes,
113
- };
114
-
115
- const componentViewModel = createViewModel(componentDefinition, componentParams, componentInfo);
116
-
117
- if (componentViewModel && componentViewModel !== componentParams &&
118
- typeof componentParams === 'object' && componentParams !== null) {
119
- wireParams(componentViewModel as object, componentParams as Record<string, unknown>, element);
120
- }
121
-
122
- if (componentViewModel && typeof (componentViewModel as Record<string, unknown>).onInit === 'function') {
123
- ((componentViewModel as Record<string, unknown>).onInit as () => void)();
124
- }
125
-
126
- const childBindingContext = asyncContext.createChildContext(componentViewModel, {
127
- extend(ctx: BindingContext) {
128
- ctx['$component'] = componentViewModel;
129
- ctx['$componentTemplateNodes'] = originalChildNodes;
130
- },
131
- });
132
-
133
- if (componentViewModel && typeof (componentViewModel as Record<string, unknown>).onDescendantsComplete === 'function') {
134
- afterRenderSub = bindingEvent.subscribe(
135
- element,
136
- bindingEvent.descendantsComplete,
137
- (componentViewModel as Record<string, unknown>).onDescendantsComplete as (value: unknown) => void,
138
- componentViewModel,
139
- );
140
- }
141
-
142
- currentViewModel = componentViewModel;
143
- ignore(() => applyBindingsToDescendants(childBindingContext, element));
144
- });
145
- });
146
-
147
- addDisposeCallback(element, () => computed.dispose());
148
-
149
- return { controlsDescendantBindings: true };
150
- },
151
- };
152
-
153
- bindingHandlers['component'] = componentHandler;
154
- allowedVirtualElementBindings['component'] = true;
155
-
156
- // ---- Custom Element Bridge ----
157
-
158
- export function getComponentNameForNode(node: Node): string | undefined {
159
- if (node.nodeType !== 1) return undefined;
160
- const tagNameLower = ((node as Element).tagName || '').toLowerCase();
161
- if (!components.isRegistered(tagNameLower)) return undefined;
162
- if (tagNameLower.indexOf('-') !== -1 || ('' + node) === '[object HTMLUnknownElement]') {
163
- return tagNameLower;
164
- }
165
- return undefined;
166
- }
167
-
168
- function isWritable(value: unknown): boolean {
169
- if (value instanceof Observable) return true;
170
- if (value instanceof Computed) return (value as Computed<unknown>).hasWriteFunction;
171
- return false;
172
- }
173
-
174
- const nativeProviderInstance = new BindingProvider();
175
-
176
- const CONTEXT_KEYWORDS = new Set([
177
- '$data', '$rawData', '$root', '$parent', '$parentContext',
178
- '$parents', '$component', '$componentTemplateNodes', '$index',
179
- ]);
180
-
181
- const OBSERVABLE_REF_PATTERN = /^\$([a-zA-Z_$][\w$]*)$/;
182
-
183
- function getComponentParamsFromCustomElement(
184
- elem: Element,
185
- bindingContext: BindingContext,
186
- ): Record<string, unknown> {
187
- const paramsAttribute = elem.getAttribute('params');
188
-
189
- if (paramsAttribute) {
190
- const keyValuePairs = parseObjectLiteral(paramsAttribute);
191
- const observableRefParams: Record<string, string> = {};
192
- const normalPairs: string[] = [];
193
-
194
- for (const kv of keyValuePairs) {
195
- const key = kv.key || kv.unknown || '';
196
- const val = (kv.value || '').trim();
197
- const match = val.match(OBSERVABLE_REF_PATTERN);
198
-
199
- if (match && !CONTEXT_KEYWORDS.has(val)) {
200
- observableRefParams[key] = match[1];
201
- } else if (key) {
202
- normalPairs.push(key + ':' + (kv.value || ''));
203
- }
204
- }
205
-
206
- const result: Record<string, unknown> = {};
207
- const rawParamComputedValues: Record<string, Computed<unknown>> = {};
208
-
209
- if (normalPairs.length > 0) {
210
- const normalParamsString = normalPairs.join(',');
211
- const params = nativeProviderInstance.parseBindingsString(
212
- normalParamsString,
213
- bindingContext,
214
- elem,
215
- { valueAccessors: true },
216
- ) as Record<string, () => unknown> | null;
217
-
218
- if (params) {
219
- for (const paramName of Object.keys(params)) {
220
- rawParamComputedValues[paramName] = new Computed(
221
- params[paramName] as () => unknown,
222
- );
223
- addDisposeCallback(elem, () => rawParamComputedValues[paramName].dispose());
224
- }
225
-
226
- for (const paramName of Object.keys(rawParamComputedValues)) {
227
- const paramValueComputed = rawParamComputedValues[paramName];
228
- const paramValue = paramValueComputed.peek();
229
-
230
- if (!paramValueComputed.isActive()) {
231
- result[paramName] = paramValue;
232
- } else {
233
- result[paramName] = new Computed({
234
- read() {
235
- return unwrapObservable(paramValueComputed.get());
236
- },
237
- write: isWritable(paramValue)
238
- ? (value: unknown) => {
239
- const currentObs = paramValueComputed.get();
240
- if (currentObs instanceof Observable) {
241
- currentObs.set(value);
242
- } else if (currentObs instanceof Computed && (currentObs as Computed<unknown>).hasWriteFunction) {
243
- (currentObs as Computed<unknown>).set(value);
244
- }
245
- }
246
- : undefined,
247
- });
248
- addDisposeCallback(elem, () => (result[paramName] as Computed<unknown>).dispose());
249
- }
250
- }
251
- }
252
- }
253
-
254
- for (const [key, propName] of Object.entries(observableRefParams)) {
255
- const dataContext = bindingContext.$data;
256
- if (dataContext && typeof dataContext === 'object') {
257
- const obs = getObservable(dataContext as object, propName);
258
- if (obs) {
259
- result[key] = obs;
260
- } else {
261
- result[key] = (dataContext as Record<string, unknown>)[propName];
262
- }
263
- }
264
- }
265
-
266
- if (!Object.prototype.hasOwnProperty.call(result, '$raw')) {
267
- result['$raw'] = rawParamComputedValues;
268
- }
269
-
270
- return result;
271
- }
272
-
273
- return { $raw: {} };
274
- }
275
-
276
- export function addBindingsForCustomElement(
277
- allBindings: Record<string, unknown> | null,
278
- node: Node,
279
- bindingContext: BindingContext,
280
- valueAccessors?: boolean,
281
- ): Record<string, unknown> | null {
282
- if (node.nodeType === 1) {
283
- const componentName = getComponentNameForNode(node);
284
- if (componentName) {
285
- allBindings = allBindings || {};
286
-
287
- if (allBindings['component']) {
288
- throw new Error('Cannot use the "component" binding on a custom element matching a component');
289
- }
290
-
291
- const componentBindingValue = {
292
- name: componentName,
293
- params: getComponentParamsFromCustomElement(node as Element, bindingContext),
294
- };
295
-
296
- allBindings['component'] = valueAccessors
297
- ? () => componentBindingValue
298
- : componentBindingValue;
299
- }
300
- }
301
-
302
- return allBindings;
303
- }
304
-
305
- // Register hooks on the binding provider to enable custom element detection
306
- setCustomElementHooks(getComponentNameForNode, addBindingsForCustomElement);
307
-
308
- // Apply display:contents to custom elements so they don't affect layout.
309
- // Opt out per-element with the "layout" attribute, or globally via options.customElementDisplayContents.
310
- addNodePreprocessor((node: Node): Node[] | void => {
311
- if (!options.customElementDisplayContents) return;
312
- if (node.nodeType === 1 && node.nodeName.includes('-')) {
313
- const el = node as HTMLElement;
314
- if (!el.hasAttribute('layout')) {
315
- el.style.display = 'contents';
316
- }
317
- }
318
- });
1
+ import { Computed } from './computed.js';
2
+ import { ignore } from './dependencyDetection.js';
3
+ import { addDisposeCallback } from './domNodeDisposal.js';
4
+ import { bindingEvent } from './bindingEvent.js';
5
+ import { BindingProvider, bindingHandlers, setCustomElementHooks, addNodePreprocessor } from './bindingProvider.js';
6
+ import type { BindingHandler } from './bindingProvider.js';
7
+ import { BindingContext } from './bindingContext.js';
8
+ import { applyBindingsToDescendants } from './applyBindings.js';
9
+ import {
10
+ virtualChildNodes,
11
+ virtualEmptyNode,
12
+ virtualSetChildren,
13
+ allowedVirtualElementBindings,
14
+ } from './virtualElements.js';
15
+ import { unwrapObservable } from './utils.js';
16
+ import { cloneNodes } from './utilsDom.js';
17
+ import { isReadableSubscribable } from './subscribable.js';
18
+ import { Observable } from './observable.js';
19
+ import { parseObjectLiteral } from './expressionRewriting.js';
20
+ import { getObservable } from './decorators.js';
21
+ import { wireParams } from './wireParams.js';
22
+ import { options } from './options.js';
23
+ import * as components from './components.js';
24
+ import type { ComponentDefinition, ComponentInfo } from './components.js';
25
+
26
+ let componentLoadingOperationUniqueId = 0;
27
+
28
+ function cloneTemplateIntoElement(
29
+ componentName: string,
30
+ componentDefinition: ComponentDefinition,
31
+ element: Node,
32
+ ): void {
33
+ const template = componentDefinition.template;
34
+ if (!template) {
35
+ throw new Error("Component '" + componentName + "' has no template");
36
+ }
37
+ const clonedNodesArray = cloneNodes(template);
38
+ virtualSetChildren(element, clonedNodesArray);
39
+ }
40
+
41
+ function createViewModel(
42
+ componentDefinition: ComponentDefinition,
43
+ componentParams: unknown,
44
+ componentInfo: ComponentInfo,
45
+ ): unknown {
46
+ const factory = componentDefinition.createViewModel;
47
+ return factory
48
+ ? factory.call(componentDefinition, componentParams, componentInfo)
49
+ : componentParams;
50
+ }
51
+
52
+ const componentHandler: BindingHandler = {
53
+ init(element, valueAccessor, _allBindings, _viewModel, bindingContext) {
54
+ let currentViewModel: unknown;
55
+ let currentLoadingOperationId: number | null;
56
+ let afterRenderSub: { dispose(): void } | null = null;
57
+
58
+ function disposeAssociatedComponentViewModel() {
59
+ const vm = currentViewModel as { dispose?: () => void } | null;
60
+ if (typeof vm?.dispose === 'function') {
61
+ vm.dispose();
62
+ }
63
+ if (afterRenderSub) {
64
+ afterRenderSub.dispose();
65
+ }
66
+ afterRenderSub = null;
67
+ currentViewModel = null;
68
+ currentLoadingOperationId = null;
69
+ }
70
+
71
+ const originalChildNodes = Array.from(virtualChildNodes(element));
72
+
73
+ virtualEmptyNode(element);
74
+ addDisposeCallback(element, disposeAssociatedComponentViewModel);
75
+
76
+ const computed = new Computed(() => {
77
+ const value = unwrapObservable(valueAccessor());
78
+ let componentName: string;
79
+ let componentParams: unknown;
80
+
81
+ if (typeof value === 'string') {
82
+ componentName = value;
83
+ } else {
84
+ const obj = value as { name: unknown; params?: unknown };
85
+ componentName = unwrapObservable(obj.name) as string;
86
+ componentParams = unwrapObservable(obj.params);
87
+ }
88
+
89
+ if (!componentName) {
90
+ throw new Error('No component name specified');
91
+ }
92
+
93
+ const asyncContext = bindingEvent.startPossiblyAsyncContentBinding(element, bindingContext);
94
+
95
+ const loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
96
+
97
+ components.get(componentName, (componentDefinition) => {
98
+ if (currentLoadingOperationId !== loadingOperationId) {
99
+ return;
100
+ }
101
+
102
+ disposeAssociatedComponentViewModel();
103
+
104
+ if (!componentDefinition) {
105
+ throw new Error("Unknown component '" + componentName + "'");
106
+ }
107
+
108
+ cloneTemplateIntoElement(componentName, componentDefinition, element);
109
+
110
+ const componentInfo: ComponentInfo = {
111
+ element,
112
+ templateNodes: originalChildNodes,
113
+ };
114
+
115
+ const componentViewModel = createViewModel(componentDefinition, componentParams, componentInfo);
116
+
117
+ if (componentViewModel && componentViewModel !== componentParams &&
118
+ typeof componentParams === 'object' && componentParams !== null) {
119
+ wireParams(componentViewModel as object, componentParams as Record<string, unknown>, element);
120
+ }
121
+
122
+ if (componentViewModel && typeof (componentViewModel as Record<string, unknown>).onInit === 'function') {
123
+ ((componentViewModel as Record<string, unknown>).onInit as () => void)();
124
+ }
125
+
126
+ const childBindingContext = asyncContext.createChildContext(componentViewModel, {
127
+ extend(ctx: BindingContext) {
128
+ ctx['$component'] = componentViewModel;
129
+ ctx['$componentTemplateNodes'] = originalChildNodes;
130
+ },
131
+ });
132
+
133
+ if (componentViewModel && typeof (componentViewModel as Record<string, unknown>).onDescendantsComplete === 'function') {
134
+ afterRenderSub = bindingEvent.subscribe(
135
+ element,
136
+ bindingEvent.descendantsComplete,
137
+ (componentViewModel as Record<string, unknown>).onDescendantsComplete as (value: unknown) => void,
138
+ componentViewModel,
139
+ );
140
+ }
141
+
142
+ currentViewModel = componentViewModel;
143
+ ignore(() => applyBindingsToDescendants(childBindingContext, element));
144
+ });
145
+ });
146
+
147
+ addDisposeCallback(element, () => computed.dispose());
148
+
149
+ return { controlsDescendantBindings: true };
150
+ },
151
+ };
152
+
153
+ bindingHandlers['component'] = componentHandler;
154
+ allowedVirtualElementBindings['component'] = true;
155
+
156
+ // ---- Custom Element Bridge ----
157
+
158
+ export function getComponentNameForNode(node: Node): string | undefined {
159
+ if (node.nodeType !== 1) return undefined;
160
+ const tagNameLower = ((node as Element).tagName || '').toLowerCase();
161
+ if (!components.isRegistered(tagNameLower)) return undefined;
162
+ if (tagNameLower.indexOf('-') !== -1 || ('' + node) === '[object HTMLUnknownElement]') {
163
+ return tagNameLower;
164
+ }
165
+ return undefined;
166
+ }
167
+
168
+ function isWritable(value: unknown): boolean {
169
+ if (value instanceof Observable) return true;
170
+ if (value instanceof Computed) return (value as Computed<unknown>).hasWriteFunction;
171
+ return false;
172
+ }
173
+
174
+ const nativeProviderInstance = new BindingProvider();
175
+
176
+ const CONTEXT_KEYWORDS = new Set([
177
+ '$data', '$rawData', '$root', '$parent', '$parentContext',
178
+ '$parents', '$component', '$componentTemplateNodes', '$index',
179
+ ]);
180
+
181
+ const OBSERVABLE_REF_PATTERN = /^\$([a-zA-Z_$][\w$]*)$/;
182
+
183
+ function getComponentParamsFromCustomElement(
184
+ elem: Element,
185
+ bindingContext: BindingContext,
186
+ ): Record<string, unknown> {
187
+ const paramsAttribute = elem.getAttribute('params');
188
+
189
+ if (paramsAttribute) {
190
+ const keyValuePairs = parseObjectLiteral(paramsAttribute);
191
+ const observableRefParams: Record<string, string> = {};
192
+ const normalPairs: string[] = [];
193
+
194
+ for (const kv of keyValuePairs) {
195
+ const key = kv.key || kv.unknown || '';
196
+ const val = (kv.value || '').trim();
197
+ const match = val.match(OBSERVABLE_REF_PATTERN);
198
+
199
+ if (match && !CONTEXT_KEYWORDS.has(val)) {
200
+ observableRefParams[key] = match[1];
201
+ } else if (key) {
202
+ normalPairs.push(key + ':' + (kv.value || ''));
203
+ }
204
+ }
205
+
206
+ const result: Record<string, unknown> = {};
207
+ const rawParamComputedValues: Record<string, Computed<unknown>> = {};
208
+
209
+ if (normalPairs.length > 0) {
210
+ const normalParamsString = normalPairs.join(',');
211
+ const params = nativeProviderInstance.parseBindingsString(
212
+ normalParamsString,
213
+ bindingContext,
214
+ elem,
215
+ { valueAccessors: true },
216
+ ) as Record<string, () => unknown> | null;
217
+
218
+ if (params) {
219
+ for (const paramName of Object.keys(params)) {
220
+ rawParamComputedValues[paramName] = new Computed(
221
+ params[paramName] as () => unknown,
222
+ );
223
+ addDisposeCallback(elem, () => rawParamComputedValues[paramName].dispose());
224
+ }
225
+
226
+ for (const paramName of Object.keys(rawParamComputedValues)) {
227
+ const paramValueComputed = rawParamComputedValues[paramName];
228
+ const paramValue = paramValueComputed.peek();
229
+
230
+ if (!paramValueComputed.isActive()) {
231
+ result[paramName] = paramValue;
232
+ } else {
233
+ result[paramName] = new Computed({
234
+ read() {
235
+ return unwrapObservable(paramValueComputed.get());
236
+ },
237
+ write: isWritable(paramValue)
238
+ ? (value: unknown) => {
239
+ const currentObs = paramValueComputed.get();
240
+ if (currentObs instanceof Observable) {
241
+ currentObs.set(value);
242
+ } else if (currentObs instanceof Computed && (currentObs as Computed<unknown>).hasWriteFunction) {
243
+ (currentObs as Computed<unknown>).set(value);
244
+ }
245
+ }
246
+ : undefined,
247
+ });
248
+ addDisposeCallback(elem, () => (result[paramName] as Computed<unknown>).dispose());
249
+ }
250
+ }
251
+ }
252
+ }
253
+
254
+ for (const [key, propName] of Object.entries(observableRefParams)) {
255
+ const dataContext = bindingContext.$data;
256
+ if (dataContext && typeof dataContext === 'object') {
257
+ const obs = getObservable(dataContext as object, propName);
258
+ if (obs) {
259
+ result[key] = obs;
260
+ } else {
261
+ result[key] = (dataContext as Record<string, unknown>)[propName];
262
+ }
263
+ }
264
+ }
265
+
266
+ if (!Object.prototype.hasOwnProperty.call(result, '$raw')) {
267
+ result['$raw'] = rawParamComputedValues;
268
+ }
269
+
270
+ return result;
271
+ }
272
+
273
+ return { $raw: {} };
274
+ }
275
+
276
+ export function addBindingsForCustomElement(
277
+ allBindings: Record<string, unknown> | null,
278
+ node: Node,
279
+ bindingContext: BindingContext,
280
+ valueAccessors?: boolean,
281
+ ): Record<string, unknown> | null {
282
+ if (node.nodeType === 1) {
283
+ const componentName = getComponentNameForNode(node);
284
+ if (componentName) {
285
+ allBindings = allBindings || {};
286
+
287
+ if (allBindings['component']) {
288
+ throw new Error('Cannot use the "component" binding on a custom element matching a component');
289
+ }
290
+
291
+ const componentBindingValue = {
292
+ name: componentName,
293
+ params: getComponentParamsFromCustomElement(node as Element, bindingContext),
294
+ };
295
+
296
+ allBindings['component'] = valueAccessors
297
+ ? () => componentBindingValue
298
+ : componentBindingValue;
299
+ }
300
+ }
301
+
302
+ return allBindings;
303
+ }
304
+
305
+ // Register hooks on the binding provider to enable custom element detection
306
+ setCustomElementHooks(getComponentNameForNode, addBindingsForCustomElement);
307
+
308
+ // Apply display:contents to custom elements so they don't affect layout.
309
+ // Opt out per-element with the "layout" attribute, or globally via options.customElementDisplayContents.
310
+ addNodePreprocessor((node: Node): Node[] | void => {
311
+ if (!options.customElementDisplayContents) return;
312
+ if (node.nodeType === 1 && node.nodeName.includes('-')) {
313
+ const el = node as HTMLElement;
314
+ if (!el.hasAttribute('layout')) {
315
+ el.style.display = 'contents';
316
+ }
317
+ }
318
+ });