@zenithbuild/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +15 -0
- package/.gitattributes +2 -0
- package/.github/ISSUE_TEMPLATE/compiler-errors-for-invalid-state-declarations.md +25 -0
- package/.github/ISSUE_TEMPLATE/new_ticket.yaml +34 -0
- package/.github/pull_request_template.md +15 -0
- package/.github/workflows/discord-changelog.yml +141 -0
- package/.github/workflows/discord-notify.yml +242 -0
- package/.github/workflows/discord-version.yml +195 -0
- package/.prettierignore +13 -0
- package/.prettierrc +21 -0
- package/.zen.d.ts +15 -0
- package/LICENSE +21 -0
- package/README.md +55 -0
- package/app/components/Button.zen +46 -0
- package/app/components/Link.zen +11 -0
- package/app/favicon.ico +0 -0
- package/app/layouts/Main.zen +59 -0
- package/app/pages/about.zen +23 -0
- package/app/pages/blog/[id].zen +53 -0
- package/app/pages/blog/index.zen +32 -0
- package/app/pages/dynamic-dx.zen +712 -0
- package/app/pages/dynamic-primitives.zen +453 -0
- package/app/pages/index.zen +154 -0
- package/app/pages/navigation-demo.zen +229 -0
- package/app/pages/posts/[...slug].zen +61 -0
- package/app/pages/primitives-demo.zen +273 -0
- package/assets/logos/0E3B5DDD-605C-4839-BB2E-DFCA8ADC9604.PNG +0 -0
- package/assets/logos/760971E5-79A1-44F9-90B9-925DF30F4278.PNG +0 -0
- package/assets/logos/8A06ED80-9ED2-4689-BCBD-13B2E95EE8E4.JPG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.PNG +0 -0
- package/assets/logos/C691FF58-ED13-4E8D-B6A3-02E835849340.svg +601 -0
- package/assets/logos/README.md +54 -0
- package/assets/logos/zen.icns +0 -0
- package/bun.lock +39 -0
- package/compiler/README.md +380 -0
- package/compiler/errors/compilerError.ts +24 -0
- package/compiler/finalize/finalizeOutput.ts +163 -0
- package/compiler/finalize/generateFinalBundle.ts +82 -0
- package/compiler/index.ts +44 -0
- package/compiler/ir/types.ts +83 -0
- package/compiler/legacy/binding.ts +254 -0
- package/compiler/legacy/bindings.ts +338 -0
- package/compiler/legacy/component-process.ts +1208 -0
- package/compiler/legacy/component.ts +301 -0
- package/compiler/legacy/event.ts +50 -0
- package/compiler/legacy/expression.ts +1149 -0
- package/compiler/legacy/mutation.ts +280 -0
- package/compiler/legacy/parse.ts +299 -0
- package/compiler/legacy/split.ts +608 -0
- package/compiler/legacy/types.ts +32 -0
- package/compiler/output/types.ts +34 -0
- package/compiler/parse/detectMapExpressions.ts +102 -0
- package/compiler/parse/parseScript.ts +22 -0
- package/compiler/parse/parseTemplate.ts +425 -0
- package/compiler/parse/parseZenFile.ts +66 -0
- package/compiler/parse/trackLoopContext.ts +82 -0
- package/compiler/runtime/dataExposure.ts +291 -0
- package/compiler/runtime/generateDOM.ts +144 -0
- package/compiler/runtime/generateHydrationBundle.ts +383 -0
- package/compiler/runtime/hydration.ts +309 -0
- package/compiler/runtime/navigation.ts +432 -0
- package/compiler/runtime/thinRuntime.ts +160 -0
- package/compiler/runtime/transformIR.ts +256 -0
- package/compiler/runtime/wrapExpression.ts +84 -0
- package/compiler/runtime/wrapExpressionWithLoop.ts +77 -0
- package/compiler/spa-build.ts +1000 -0
- package/compiler/test/validate-test.ts +104 -0
- package/compiler/transform/generateBindings.ts +47 -0
- package/compiler/transform/generateHTML.ts +28 -0
- package/compiler/transform/transformNode.ts +126 -0
- package/compiler/transform/transformTemplate.ts +38 -0
- package/compiler/validate/validateExpressions.ts +168 -0
- package/core/index.ts +135 -0
- package/core/lifecycle/index.ts +49 -0
- package/core/lifecycle/zen-mount.ts +182 -0
- package/core/lifecycle/zen-unmount.ts +88 -0
- package/core/reactivity/index.ts +54 -0
- package/core/reactivity/tracking.ts +167 -0
- package/core/reactivity/zen-batch.ts +57 -0
- package/core/reactivity/zen-effect.ts +139 -0
- package/core/reactivity/zen-memo.ts +146 -0
- package/core/reactivity/zen-ref.ts +52 -0
- package/core/reactivity/zen-signal.ts +121 -0
- package/core/reactivity/zen-state.ts +180 -0
- package/core/reactivity/zen-untrack.ts +44 -0
- package/docs/COMMENTS.md +111 -0
- package/docs/COMMITS.md +36 -0
- package/docs/CONTRIBUTING.md +116 -0
- package/docs/STYLEGUIDE.md +62 -0
- package/package.json +44 -0
- package/router/index.ts +76 -0
- package/router/manifest.ts +314 -0
- package/router/navigation/ZenLink.zen +231 -0
- package/router/navigation/index.ts +78 -0
- package/router/navigation/zen-link.ts +584 -0
- package/router/runtime.ts +458 -0
- package/router/types.ts +168 -0
- package/runtime/build.ts +17 -0
- package/runtime/serve.ts +93 -0
- package/scripts/webhook-proxy.ts +213 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// compiler/bindings.ts
|
|
2
|
+
// Phase 2: Object-style dynamic attribute bindings with quoted expressions
|
|
3
|
+
// Supports :class and :value attributes with synchronous, deterministic updates
|
|
4
|
+
|
|
5
|
+
export function generateAttributeBindingRuntime(bindings: Array<{ type: 'class' | 'value'; expression: string }>): string {
|
|
6
|
+
if (bindings.length === 0) {
|
|
7
|
+
return ''; // No bindings, no runtime needed
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Generate unique expression IDs for tracking
|
|
11
|
+
const expressionIds = bindings.map((_, i) => `expr_${i}`);
|
|
12
|
+
const expressionsStr = JSON.stringify(bindings.map(b => b.expression));
|
|
13
|
+
const typesStr = JSON.stringify(bindings.map(b => b.type));
|
|
14
|
+
|
|
15
|
+
return `
|
|
16
|
+
// Phase 2: Attribute binding runtime - synchronous, deterministic updates
|
|
17
|
+
// Note: 'use strict' is omitted to allow 'with' statement for expression evaluation
|
|
18
|
+
(function() {
|
|
19
|
+
|
|
20
|
+
// Store all binding elements and their expressions
|
|
21
|
+
const bindingExpressions = ${expressionsStr};
|
|
22
|
+
const bindingTypes = ${typesStr};
|
|
23
|
+
const bindingElements = [];
|
|
24
|
+
|
|
25
|
+
// Reactive state proxy - tracks property access and updates DOM synchronously
|
|
26
|
+
// Initialize with empty object - properties will be added dynamically
|
|
27
|
+
const stateTarget = {};
|
|
28
|
+
const stateProxy = new Proxy(stateTarget, {
|
|
29
|
+
set(target, prop, value) {
|
|
30
|
+
const oldValue = target[prop];
|
|
31
|
+
target[prop] = value;
|
|
32
|
+
|
|
33
|
+
// Log state change for debugging
|
|
34
|
+
// console.log('[Zenith] State change:', prop, '=', value);
|
|
35
|
+
|
|
36
|
+
// Synchronously update all affected bindings
|
|
37
|
+
bindingElements.forEach(binding => {
|
|
38
|
+
try {
|
|
39
|
+
// Re-evaluate expression in context of current state
|
|
40
|
+
// Pass target (the state object) as parameter to the evaluator function
|
|
41
|
+
// If this binding has instance state, merge it with global state
|
|
42
|
+
const mergedState = binding.instanceState
|
|
43
|
+
? Object.assign({}, target, binding.instanceState)
|
|
44
|
+
: target;
|
|
45
|
+
const result = binding.fn(mergedState);
|
|
46
|
+
|
|
47
|
+
if (binding.type === 'class') {
|
|
48
|
+
updateClassBinding(binding.el, result);
|
|
49
|
+
// console.log('[Zenith] Updated :class binding for element:', binding.el, 'result:', result);
|
|
50
|
+
} else if (binding.type === 'value') {
|
|
51
|
+
updateValueBinding(binding.el, result);
|
|
52
|
+
// console.log('[Zenith] Updated :value binding for element:', binding.el, 'result:', result);
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
// Log errors for debugging (Phase 2: graceful degradation)
|
|
56
|
+
console.warn('[Zenith] Binding evaluation error:', e, 'for expression:', binding.expression);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return true;
|
|
61
|
+
},
|
|
62
|
+
get(target, prop) {
|
|
63
|
+
// Return undefined for missing properties (don't throw errors)
|
|
64
|
+
return target[prop];
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Make stateProxy available globally as 'state'
|
|
69
|
+
window.state = stateProxy;
|
|
70
|
+
|
|
71
|
+
// Function to update attribute bindings for a specific component instance
|
|
72
|
+
// Called when instance-scoped state changes
|
|
73
|
+
function updateAttributeBindingsForInstance(instanceId) {
|
|
74
|
+
const instanceRoot = document.querySelector('[data-zen-instance="' + instanceId + '"]');
|
|
75
|
+
if (!instanceRoot) return;
|
|
76
|
+
|
|
77
|
+
// Update all bindings within this instance
|
|
78
|
+
bindingElements.forEach(binding => {
|
|
79
|
+
// Check if this binding belongs to the instance
|
|
80
|
+
const bindingInstanceRoot = findInstanceRoot(binding.el);
|
|
81
|
+
if (bindingInstanceRoot === instanceRoot) {
|
|
82
|
+
try {
|
|
83
|
+
const instanceState = getInstanceStateForElement(binding.el);
|
|
84
|
+
const mergedState = instanceState
|
|
85
|
+
? Object.assign({}, stateProxy, instanceState)
|
|
86
|
+
: stateProxy;
|
|
87
|
+
const result = binding.fn(mergedState);
|
|
88
|
+
|
|
89
|
+
if (binding.type === 'class') {
|
|
90
|
+
updateClassBinding(binding.el, result);
|
|
91
|
+
} else if (binding.type === 'value') {
|
|
92
|
+
updateValueBinding(binding.el, result);
|
|
93
|
+
}
|
|
94
|
+
} catch (e) {
|
|
95
|
+
console.warn('[Zenith] Attribute binding evaluation error:', e, 'for expression:', binding.expression);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Expose update function globally so text binding runtime can trigger it
|
|
102
|
+
window.__zen_update_attribute_bindings = updateAttributeBindingsForInstance;
|
|
103
|
+
|
|
104
|
+
// Helper: Evaluate class binding expression
|
|
105
|
+
// Handles: objects, strings, empty objects, falsy values
|
|
106
|
+
// Preserves existing static classes from the class attribute
|
|
107
|
+
function updateClassBinding(el, result) {
|
|
108
|
+
// Store static classes on first update (from class attribute)
|
|
109
|
+
if (!el._zenStaticClasses) {
|
|
110
|
+
const staticClasses = el.getAttribute('class') || '';
|
|
111
|
+
el._zenStaticClasses = staticClasses.split(/\\s+/).filter(c => c);
|
|
112
|
+
}
|
|
113
|
+
const staticClassList = el._zenStaticClasses;
|
|
114
|
+
|
|
115
|
+
if (typeof result === 'string') {
|
|
116
|
+
// String value: treat as raw class names, merge with static classes
|
|
117
|
+
const dynamicClasses = result.split(/\\s+/).filter(c => c);
|
|
118
|
+
el.className = [...staticClassList, ...dynamicClasses].join(' ').trim();
|
|
119
|
+
} else if (result && typeof result === 'object' && !Array.isArray(result)) {
|
|
120
|
+
// Object value: extract keys with true values
|
|
121
|
+
const dynamicClasses = [];
|
|
122
|
+
for (const key in result) {
|
|
123
|
+
if (result.hasOwnProperty(key) && result[key] === true) {
|
|
124
|
+
dynamicClasses.push(key);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Merge static and dynamic classes
|
|
128
|
+
el.className = [...staticClassList, ...dynamicClasses].join(' ').trim();
|
|
129
|
+
} else {
|
|
130
|
+
// Falsy, null, undefined, or non-object: keep only static classes
|
|
131
|
+
el.className = staticClassList.join(' ').trim();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Helper: Evaluate value binding expression
|
|
136
|
+
// Handles: primitives, falsy values
|
|
137
|
+
function updateValueBinding(el, result) {
|
|
138
|
+
if (result === null || result === undefined) {
|
|
139
|
+
el.value = '';
|
|
140
|
+
} else {
|
|
141
|
+
el.value = String(result);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Helper: Safely evaluate expression string
|
|
146
|
+
// Creates a function that evaluates the expression with state properties in scope
|
|
147
|
+
// Supports both global state (via state object) and instance-scoped state (via window)
|
|
148
|
+
function createEvaluator(expression) {
|
|
149
|
+
// Trim whitespace from expression
|
|
150
|
+
let trimmed = expression.trim();
|
|
151
|
+
|
|
152
|
+
// Check if expression is a quoted string (single or double quotes)
|
|
153
|
+
// If so, unquote it and check if it's a simple identifier
|
|
154
|
+
let isSimpleIdentifier = false;
|
|
155
|
+
let evalExpression = trimmed;
|
|
156
|
+
|
|
157
|
+
// Handle quoted strings: "username" or 'username' -> username
|
|
158
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
159
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
160
|
+
// Extract the unquoted value
|
|
161
|
+
const unquoted = trimmed.slice(1, -1);
|
|
162
|
+
// Check if unquoted value is a simple identifier
|
|
163
|
+
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(unquoted)) {
|
|
164
|
+
isSimpleIdentifier = true;
|
|
165
|
+
evalExpression = unquoted; // Use unquoted identifier for evaluation
|
|
166
|
+
}
|
|
167
|
+
// Otherwise, treat as string literal (e.g., "'static-class'" -> "static-class")
|
|
168
|
+
} else {
|
|
169
|
+
// Not quoted: check if it's a simple identifier
|
|
170
|
+
isSimpleIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(trimmed);
|
|
171
|
+
if (isSimpleIdentifier) {
|
|
172
|
+
evalExpression = trimmed; // Already unquoted identifier
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// Create a function that evaluates the expression
|
|
178
|
+
// The expression is written as if state properties are directly accessible
|
|
179
|
+
// We use Function constructor with 'with' statement to make state properties available
|
|
180
|
+
// Note: 'with' is deprecated but necessary for this use case in non-strict mode
|
|
181
|
+
return function(state) {
|
|
182
|
+
try {
|
|
183
|
+
// Use window.__zen_eval_expr for consistent expression evaluation
|
|
184
|
+
// This handles window properties (state variables) correctly
|
|
185
|
+
if (typeof window !== 'undefined' && window.__zen_eval_expr) {
|
|
186
|
+
return window.__zen_eval_expr(evalExpression);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Fallback: Merge state with window to access instance-scoped state variables
|
|
190
|
+
// This allows expressions to reference both global state and instance-scoped state
|
|
191
|
+
// Copy window properties that look like instance-scoped state to the merged context
|
|
192
|
+
const mergedContext = Object.assign({}, state);
|
|
193
|
+
for (const key in window) {
|
|
194
|
+
if (key.startsWith('__zen_comp_') && !(key in mergedContext)) {
|
|
195
|
+
mergedContext[key] = window[key];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Use Function constructor to create evaluator
|
|
200
|
+
// The 'with' statement makes state properties and instance-scoped state available as variables
|
|
201
|
+
// This allows expressions like "{ active: isActive }" where isActive refers to state.isActive
|
|
202
|
+
// or instance-scoped variables like __zen_comp_0_clicks
|
|
203
|
+
const func = new Function('state',
|
|
204
|
+
'try {' +
|
|
205
|
+
' with (state) {' +
|
|
206
|
+
' return (' + evalExpression + ');' +
|
|
207
|
+
' }' +
|
|
208
|
+
'} catch (e) {' +
|
|
209
|
+
' console.warn("[Zenith] Expression evaluation error:", ' + JSON.stringify(trimmed) + ', e);' +
|
|
210
|
+
' return null;' +
|
|
211
|
+
'}'
|
|
212
|
+
);
|
|
213
|
+
const result = func(mergedContext);
|
|
214
|
+
// console.log('[Zenith] Evaluated expression:', trimmed, 'result:', result, 'state:', state);
|
|
215
|
+
return result;
|
|
216
|
+
} catch (e) {
|
|
217
|
+
// Last resort: return safe default
|
|
218
|
+
console.warn('Expression evaluation error:', trimmed, e);
|
|
219
|
+
const bindingIndex = bindingExpressions.indexOf(expression);
|
|
220
|
+
return bindingIndex >= 0 && bindingTypes[bindingIndex] === 'class' ? {} : '';
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
} catch (e) {
|
|
224
|
+
// If expression is invalid, return a function that returns empty string/object
|
|
225
|
+
console.warn('Invalid binding expression:', expression, e);
|
|
226
|
+
const bindingIndex = bindingExpressions.indexOf(expression);
|
|
227
|
+
return function() {
|
|
228
|
+
return bindingIndex >= 0 && bindingTypes[bindingIndex] === 'class' ? {} : '';
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Helper: Find component instance root for an element
|
|
234
|
+
function findInstanceRoot(el) {
|
|
235
|
+
let current = el;
|
|
236
|
+
while (current) {
|
|
237
|
+
if (current.hasAttribute && current.hasAttribute('data-zen-instance')) {
|
|
238
|
+
return current;
|
|
239
|
+
}
|
|
240
|
+
current = current.parentElement;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Helper: Get instance-scoped state for an element
|
|
246
|
+
function getInstanceStateForElement(el) {
|
|
247
|
+
const instanceRoot = findInstanceRoot(el);
|
|
248
|
+
if (instanceRoot) {
|
|
249
|
+
const instanceId = instanceRoot.getAttribute('data-zen-instance');
|
|
250
|
+
if (instanceId && window.__zen_instances && window.__zen_instances[instanceId]) {
|
|
251
|
+
return window.__zen_instances[instanceId];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Enhanced evaluator that supports both global and instance-scoped state
|
|
258
|
+
function createEnhancedEvaluator(expression, instanceState) {
|
|
259
|
+
const baseEvaluator = createEvaluator(expression);
|
|
260
|
+
return function(state) {
|
|
261
|
+
// Merge global state and instance state
|
|
262
|
+
const mergedState = Object.assign({}, state);
|
|
263
|
+
if (instanceState) {
|
|
264
|
+
Object.assign(mergedState, instanceState);
|
|
265
|
+
}
|
|
266
|
+
// Also check window for instance-scoped state variables (e.g., __zen_comp_0_clicks)
|
|
267
|
+
// These are set up by the binding runtime
|
|
268
|
+
return baseEvaluator(mergedState);
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Initialize bindings after DOM is ready
|
|
273
|
+
function initializeBindings() {
|
|
274
|
+
// console.log('[Zenith] Initializing attribute bindings...');
|
|
275
|
+
|
|
276
|
+
// Find all elements with data-zen-class or data-zen-value attributes
|
|
277
|
+
const classElements = document.querySelectorAll('[data-zen-class]');
|
|
278
|
+
const valueElements = document.querySelectorAll('[data-zen-value]');
|
|
279
|
+
|
|
280
|
+
// console.log('[Zenith] Found', classElements.length, ':class bindings and', valueElements.length, ':value bindings');
|
|
281
|
+
|
|
282
|
+
// Process :class bindings
|
|
283
|
+
classElements.forEach((el) => {
|
|
284
|
+
const expression = el.getAttribute('data-zen-class');
|
|
285
|
+
if (expression) {
|
|
286
|
+
// console.log('[Zenith] Setting up :class binding:', expression, 'for element:', el);
|
|
287
|
+
const instanceState = getInstanceStateForElement(el);
|
|
288
|
+
const fn = createEnhancedEvaluator(expression, instanceState);
|
|
289
|
+
|
|
290
|
+
// Use merged state for initial evaluation
|
|
291
|
+
const mergedState = Object.assign({}, stateProxy);
|
|
292
|
+
if (instanceState) {
|
|
293
|
+
Object.assign(mergedState, instanceState);
|
|
294
|
+
}
|
|
295
|
+
const result = fn(mergedState);
|
|
296
|
+
updateClassBinding(el, result);
|
|
297
|
+
bindingElements.push({ el: el, type: 'class', expression, fn, instanceState });
|
|
298
|
+
// console.log('[Zenith] Initial :class result:', result, 'applied classes:', el.className);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Process :value bindings
|
|
303
|
+
valueElements.forEach((el) => {
|
|
304
|
+
const expression = el.getAttribute('data-zen-value');
|
|
305
|
+
if (expression) {
|
|
306
|
+
// console.log('[Zenith] Setting up :value binding:', expression, 'for element:', el);
|
|
307
|
+
const instanceState = getInstanceStateForElement(el);
|
|
308
|
+
const fn = createEnhancedEvaluator(expression, instanceState);
|
|
309
|
+
|
|
310
|
+
// Use merged state for initial evaluation
|
|
311
|
+
const mergedState = Object.assign({}, stateProxy);
|
|
312
|
+
if (instanceState) {
|
|
313
|
+
Object.assign(mergedState, instanceState);
|
|
314
|
+
}
|
|
315
|
+
const result = fn(mergedState);
|
|
316
|
+
updateValueBinding(el, result);
|
|
317
|
+
bindingElements.push({ el: el, type: 'value', expression, fn, instanceState });
|
|
318
|
+
// console.log('[Zenith] Initial :value result:', result, 'applied value:', el.value);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Instance state proxies are set up by the text binding runtime
|
|
323
|
+
// Attribute binding updates are triggered via window.__zen_update_attribute_bindings
|
|
324
|
+
// when instance-scoped state changes
|
|
325
|
+
|
|
326
|
+
// console.log('[Zenith] Initialized', bindingElements.length, 'bindings. State object:', stateProxy);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Initialize when DOM is ready
|
|
330
|
+
if (document.readyState === 'loading') {
|
|
331
|
+
document.addEventListener('DOMContentLoaded', initializeBindings);
|
|
332
|
+
} else {
|
|
333
|
+
initializeBindings();
|
|
334
|
+
}
|
|
335
|
+
})();
|
|
336
|
+
`;
|
|
337
|
+
}
|
|
338
|
+
|