@sigx/runtime-core 0.1.5 → 0.1.6

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 (42) hide show
  1. package/dist/app-types.d.ts +35 -15
  2. package/dist/app-types.d.ts.map +1 -1
  3. package/dist/app.d.ts +4 -8
  4. package/dist/app.d.ts.map +1 -1
  5. package/dist/component.d.ts +127 -38
  6. package/dist/component.d.ts.map +1 -1
  7. package/dist/compound.d.ts +34 -0
  8. package/dist/compound.d.ts.map +1 -0
  9. package/dist/di/factory.d.ts +3 -2
  10. package/dist/di/factory.d.ts.map +1 -1
  11. package/dist/di/injectable.d.ts +80 -6
  12. package/dist/di/injectable.d.ts.map +1 -1
  13. package/dist/hydration/index.d.ts +88 -0
  14. package/dist/hydration/index.d.ts.map +1 -0
  15. package/dist/index.d.ts +3 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +458 -690
  18. package/dist/index.js.map +1 -1
  19. package/dist/jsx-runtime.d.ts +3 -2
  20. package/dist/jsx-runtime.d.ts.map +1 -1
  21. package/dist/lazy.d.ts.map +1 -1
  22. package/dist/model.d.ts +68 -0
  23. package/dist/model.d.ts.map +1 -0
  24. package/dist/platform.d.ts +9 -9
  25. package/dist/platform.d.ts.map +1 -1
  26. package/dist/renderer.d.ts +1 -3
  27. package/dist/renderer.d.ts.map +1 -1
  28. package/dist/utils/is-component.d.ts +30 -0
  29. package/dist/utils/is-component.d.ts.map +1 -0
  30. package/dist/utils/normalize.d.ts +4 -1
  31. package/dist/utils/normalize.d.ts.map +1 -1
  32. package/dist/utils/props-accessor.d.ts +6 -9
  33. package/dist/utils/props-accessor.d.ts.map +1 -1
  34. package/package.json +7 -6
  35. package/dist/sheet.d.ts +0 -51
  36. package/dist/sheet.d.ts.map +0 -1
  37. package/dist/stores/store.d.ts +0 -70
  38. package/dist/stores/store.d.ts.map +0 -1
  39. package/dist/styled.d.ts +0 -15
  40. package/dist/styled.d.ts.map +0 -1
  41. package/dist/utils/component-helpers.d.ts +0 -38
  42. package/dist/utils/component-helpers.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,107 +1,139 @@
1
- import { detectAccess, effect, effectScope, signal, signal as signal$1, untrack, watch } from "@sigx/reactivity";
2
-
3
- //#region src/platform.ts
4
- let platformSyncProcessor = null;
5
- /**
6
- * Set the platform-specific sync processor for intrinsic elements.
7
- * Called by runtime-dom to handle checkbox/radio/select sync bindings.
8
- */
9
- function setPlatformSyncProcessor(fn) {
10
- platformSyncProcessor = fn;
1
+ import { detectAccess, effect, isComputed, signal, signal as signal$1, untrack } from "@sigx/reactivity";
2
+ var platformModelProcessor = null;
3
+ function setPlatformModelProcessor(fn) {
4
+ platformModelProcessor = fn;
11
5
  }
12
- /**
13
- * Get the current platform sync processor (for internal use).
14
- */
15
- function getPlatformSyncProcessor() {
16
- return platformSyncProcessor;
6
+ function getPlatformModelProcessor() {
7
+ return platformModelProcessor;
17
8
  }
18
-
19
- //#endregion
20
- //#region src/plugins.ts
21
- const plugins = [];
9
+ var plugins = [];
22
10
  function registerComponentPlugin(plugin) {
23
11
  plugins.push(plugin);
24
12
  }
25
- /**
26
- * Get all registered plugins (internal use)
27
- */
28
13
  function getComponentPlugins() {
29
14
  return plugins;
30
15
  }
31
- const contextExtensions = [];
32
- /**
33
- * Register a function that will be called to extend every component context.
34
- * Extensions are called in order of registration.
35
- *
36
- * @example
37
- * ```ts
38
- * // In @sigx/server-renderer/client
39
- * registerContextExtension((ctx) => {
40
- * ctx.ssr = { load: () => {} };
41
- * });
42
- * ```
43
- */
16
+ var contextExtensions = [];
44
17
  function registerContextExtension(extension) {
45
18
  contextExtensions.push(extension);
46
19
  }
47
- /**
48
- * Apply all registered context extensions to a context object.
49
- * Called internally by the renderer when creating component contexts.
50
- */
51
20
  function applyContextExtensions(ctx) {
52
21
  for (const extension of contextExtensions) extension(ctx);
53
22
  }
54
-
55
- //#endregion
56
- //#region src/app.ts
57
- const isDev = typeof process !== "undefined" && true || true;
58
- /**
59
- * Unique symbol for app context injection
60
- */
61
- const AppContextKey = Symbol("sigx:app");
62
- let defaultMountFn = null;
63
- /**
64
- * Set the default mount function for the platform.
65
- * Called by platform packages (runtime-dom, runtime-terminal) on import.
66
- *
67
- * @example
68
- * ```typescript
69
- * // In @sigx/runtime-dom
70
- * import { setDefaultMount } from '@sigx/runtime-core';
71
- * setDefaultMount(domMount);
72
- * ```
73
- */
23
+ var currentComponentContext = null;
24
+ function getCurrentInstance() {
25
+ return currentComponentContext;
26
+ }
27
+ function setCurrentInstance(ctx) {
28
+ const prev = currentComponentContext;
29
+ currentComponentContext = ctx;
30
+ return prev;
31
+ }
32
+ function onMounted(fn) {
33
+ if (currentComponentContext) currentComponentContext.onMounted(fn);
34
+ else console.warn("onMounted called outside of component setup");
35
+ }
36
+ function onUnmounted(fn) {
37
+ if (currentComponentContext) currentComponentContext.onUnmounted(fn);
38
+ else console.warn("onUnmounted called outside of component setup");
39
+ }
40
+ function onCreated(fn) {
41
+ if (currentComponentContext) currentComponentContext.onCreated(fn);
42
+ else console.warn("onCreated called outside of component setup");
43
+ }
44
+ function onUpdated(fn) {
45
+ if (currentComponentContext) currentComponentContext.onUpdated(fn);
46
+ else console.warn("onUpdated called outside of component setup");
47
+ }
48
+ var componentRegistry = /* @__PURE__ */ new Map();
49
+ function getComponentMeta(factory) {
50
+ return componentRegistry.get(factory);
51
+ }
52
+ function createPropsProxy(target, onAccess) {
53
+ return new Proxy(target, { get(obj, prop) {
54
+ if (typeof prop === "string" && onAccess) onAccess(prop);
55
+ return obj[prop];
56
+ } });
57
+ }
58
+ function component(setup, options) {
59
+ const factory = function(props) {
60
+ return {
61
+ type: factory,
62
+ props: props || {},
63
+ key: props?.key || null,
64
+ children: [],
65
+ dom: null
66
+ };
67
+ };
68
+ factory.__setup = setup;
69
+ factory.__name = options?.name;
70
+ factory.__props = null;
71
+ factory.__events = null;
72
+ factory.__ref = null;
73
+ factory.__slots = null;
74
+ componentRegistry.set(factory, {
75
+ name: options?.name,
76
+ setup
77
+ });
78
+ getComponentPlugins().forEach((p) => p.onDefine?.(options?.name, factory, setup));
79
+ return factory;
80
+ }
81
+ var globalInstances = /* @__PURE__ */ new Map();
82
+ var appContextToken = Symbol("sigx:appContext");
83
+ function lookupProvided(token) {
84
+ const ctx = getCurrentInstance();
85
+ if (!ctx) return;
86
+ let current = ctx;
87
+ while (current) {
88
+ if (current.provides && current.provides.has(token)) return current.provides.get(token);
89
+ current = current.parent;
90
+ }
91
+ }
92
+ function provideAtComponent(token, value) {
93
+ const ctx = getCurrentInstance();
94
+ if (!ctx) throw new Error("defineProvide must be called inside a component setup function");
95
+ if (!ctx.provides) ctx.provides = /* @__PURE__ */ new Map();
96
+ ctx.provides.set(token, value);
97
+ }
98
+ function defineInjectable(factory) {
99
+ const token = Symbol();
100
+ const useFn = (() => {
101
+ const provided = lookupProvided(token);
102
+ if (provided !== void 0) return provided;
103
+ if (!globalInstances.has(token)) globalInstances.set(token, factory());
104
+ return globalInstances.get(token);
105
+ });
106
+ useFn._factory = factory;
107
+ useFn._token = token;
108
+ return useFn;
109
+ }
110
+ function defineProvide(useFn, factory) {
111
+ const actualFactory = factory ?? useFn._factory;
112
+ const token = useFn._token;
113
+ if (!actualFactory || !token) throw new Error("defineProvide must be called with a function created by defineInjectable");
114
+ const instance = actualFactory();
115
+ provideAtComponent(token, instance);
116
+ return instance;
117
+ }
118
+ function useAppContext() {
119
+ return lookupProvided(appContextToken) ?? null;
120
+ }
121
+ function getAppContextToken() {
122
+ return appContextToken;
123
+ }
124
+ function provideAppContext(ctx, appContext) {
125
+ if (!ctx.provides) ctx.provides = /* @__PURE__ */ new Map();
126
+ ctx.provides.set(appContextToken, appContext);
127
+ if (appContext.provides) for (const [token, value] of appContext.provides) ctx.provides.set(token, value);
128
+ }
129
+ var isDev = typeof process !== "undefined" && process.env.NODE_ENV !== "production" || true;
130
+ var defaultMountFn = null;
74
131
  function setDefaultMount(mountFn) {
75
132
  defaultMountFn = mountFn;
76
133
  }
77
- /**
78
- * Get the current default mount function.
79
- * @internal
80
- */
81
134
  function getDefaultMount() {
82
135
  return defaultMountFn;
83
136
  }
84
- /**
85
- * Create an application instance.
86
- *
87
- * @example
88
- * ```tsx
89
- * import { defineApp, defineInjectable } from '@sigx/runtime-core';
90
- * import { render } from '@sigx/runtime-dom';
91
- *
92
- * // Define an injectable service
93
- * const useApiConfig = defineInjectable(() => ({ baseUrl: 'https://api.example.com' }));
94
- *
95
- * const app = defineApp(<App />);
96
- *
97
- * app.use(myPlugin, { option: 'value' });
98
- *
99
- * // Provide using the injectable token (works with inject())
100
- * app.provide(useApiConfig, { baseUrl: 'https://custom.api.com' });
101
- *
102
- * app.mount(document.getElementById('app')!, render);
103
- * ```
104
- */
105
137
  function defineApp(rootComponent) {
106
138
  const installedPlugins = /* @__PURE__ */ new Set();
107
139
  const context = {
@@ -126,11 +158,13 @@ function defineApp(rootComponent) {
126
158
  else if (isDev) console.warn("Invalid plugin: must be a function or have an install() method.");
127
159
  return app;
128
160
  },
129
- provide(token, value) {
130
- const actualToken = token?._token ?? token;
131
- if (isDev && context.provides.has(actualToken)) console.warn(`App-level provide: token is being overwritten.`);
132
- context.provides.set(actualToken, value);
133
- return app;
161
+ defineProvide(useFn, factory) {
162
+ const actualFactory = factory ?? useFn._factory;
163
+ const token = useFn._token;
164
+ if (!actualFactory || !token) throw new Error("defineProvide must be called with a function created by defineInjectable");
165
+ const instance = actualFactory();
166
+ context.provides.set(token, instance);
167
+ return instance;
134
168
  },
135
169
  hook(hooks) {
136
170
  context.hooks.push(hooks);
@@ -167,15 +201,16 @@ function defineApp(rootComponent) {
167
201
  },
168
202
  get _container() {
169
203
  return container;
204
+ },
205
+ get _rootComponent() {
206
+ return rootComponent;
170
207
  }
171
208
  };
172
209
  context.app = app;
210
+ const appContextToken = getAppContextToken();
211
+ context.provides.set(appContextToken, context);
173
212
  return app;
174
213
  }
175
- /**
176
- * Notify all app hooks that a component was created.
177
- * Called by the renderer after setup() returns.
178
- */
179
214
  function notifyComponentCreated(context, instance) {
180
215
  if (!context) return;
181
216
  for (const hooks of context.hooks) try {
@@ -184,10 +219,6 @@ function notifyComponentCreated(context, instance) {
184
219
  handleHookError(context, err, instance, "onComponentCreated");
185
220
  }
186
221
  }
187
- /**
188
- * Notify all app hooks that a component was mounted.
189
- * Called by the renderer after mount hooks run.
190
- */
191
222
  function notifyComponentMounted(context, instance) {
192
223
  if (!context) return;
193
224
  for (const hooks of context.hooks) try {
@@ -196,10 +227,6 @@ function notifyComponentMounted(context, instance) {
196
227
  handleHookError(context, err, instance, "onComponentMounted");
197
228
  }
198
229
  }
199
- /**
200
- * Notify all app hooks that a component was unmounted.
201
- * Called by the renderer before cleanup.
202
- */
203
230
  function notifyComponentUnmounted(context, instance) {
204
231
  if (!context) return;
205
232
  for (const hooks of context.hooks) try {
@@ -208,10 +235,6 @@ function notifyComponentUnmounted(context, instance) {
208
235
  handleHookError(context, err, instance, "onComponentUnmounted");
209
236
  }
210
237
  }
211
- /**
212
- * Notify all app hooks that a component updated.
213
- * Called by the renderer after re-render.
214
- */
215
238
  function notifyComponentUpdated(context, instance) {
216
239
  if (!context) return;
217
240
  for (const hooks of context.hooks) try {
@@ -220,10 +243,6 @@ function notifyComponentUpdated(context, instance) {
220
243
  handleHookError(context, err, instance, "onComponentUpdated");
221
244
  }
222
245
  }
223
- /**
224
- * Handle an error in a component. Returns true if the error was handled.
225
- * Called by the renderer when an error occurs in setup or render.
226
- */
227
246
  function handleComponentError(context, err, instance, info) {
228
247
  if (!context) return false;
229
248
  for (const hooks of context.hooks) try {
@@ -238,104 +257,53 @@ function handleComponentError(context, err, instance, info) {
238
257
  }
239
258
  return false;
240
259
  }
241
- /**
242
- * Handle errors that occur in hooks themselves
243
- */
244
260
  function handleHookError(context, err, instance, hookName) {
245
261
  console.error(`Error in ${hookName} hook:`, err);
246
262
  if (context.config.errorHandler) try {
247
263
  context.config.errorHandler(err, instance, `plugin hook: ${hookName}`);
248
264
  } catch {}
249
265
  }
250
-
251
- //#endregion
252
- //#region src/component.ts
253
- let currentComponentContext = null;
254
- function getCurrentInstance() {
255
- return currentComponentContext;
256
- }
257
- function setCurrentInstance(ctx) {
258
- const prev = currentComponentContext;
259
- currentComponentContext = ctx;
260
- return prev;
266
+ function compound(main, sub) {
267
+ return Object.assign(main, sub);
261
268
  }
262
- function onMount(fn) {
263
- if (currentComponentContext) currentComponentContext.onMount(fn);
264
- else console.warn("onMount called outside of component setup");
269
+ var MODEL_SYMBOL = Symbol.for("sigx.model");
270
+ function createModel(tuple, updateHandler) {
271
+ const [obj, key] = tuple;
272
+ return {
273
+ get value() {
274
+ return obj[key];
275
+ },
276
+ set value(v) {
277
+ updateHandler(v);
278
+ },
279
+ get binding() {
280
+ return [
281
+ obj,
282
+ key,
283
+ updateHandler
284
+ ];
285
+ },
286
+ [MODEL_SYMBOL]: true
287
+ };
265
288
  }
266
- function onCleanup(fn) {
267
- if (currentComponentContext) currentComponentContext.onCleanup(fn);
268
- else console.warn("onCleanup called outside of component setup");
289
+ function createModelFromBinding(binding) {
290
+ const [obj, key, handler] = binding;
291
+ return createModel([obj, key], handler);
269
292
  }
270
- const componentRegistry = /* @__PURE__ */ new Map();
271
- /**
272
- * Get component metadata (for DevTools)
273
- */
274
- function getComponentMeta(factory) {
275
- return componentRegistry.get(factory);
293
+ function isModel(value) {
294
+ return value !== null && typeof value === "object" && MODEL_SYMBOL in value && value[MODEL_SYMBOL] === true;
276
295
  }
277
- /**
278
- * Helper to create a proxy that tracks property access
279
- */
280
- function createPropsProxy(target, onAccess) {
281
- return new Proxy(target, { get(obj, prop) {
282
- if (typeof prop === "string" && onAccess) onAccess(prop);
283
- return obj[prop];
284
- } });
296
+ function getModelSymbol() {
297
+ return MODEL_SYMBOL;
285
298
  }
286
- /**
287
- * Define a component. Returns a JSX factory function.
288
- *
289
- * @param setup - Setup function that receives context and returns a render function
290
- * @param options - Optional configuration (e.g., name for DevTools)
291
- *
292
- * @example
293
- * ```tsx
294
- * type CardProps = DefineProp<"title", string> & DefineSlot<"header">;
295
- *
296
- * export const Card = defineComponent<CardProps>((ctx) => {
297
- * const { title } = ctx.props;
298
- * const { slots } = ctx;
299
- *
300
- * return () => (
301
- * <div class="card">
302
- * {slots.header?.() ?? <h2>{title}</h2>}
303
- * {slots.default()}
304
- * </div>
305
- * );
306
- * });
307
- * ```
308
- */
309
- function defineComponent(setup, options) {
310
- const factory = function(props) {
311
- return {
312
- type: factory,
313
- props: props || {},
314
- key: props?.key || null,
315
- children: [],
316
- dom: null
317
- };
318
- };
319
- factory.__setup = setup;
320
- factory.__name = options?.name;
321
- factory.__props = null;
322
- factory.__events = null;
323
- factory.__ref = null;
324
- factory.__slots = null;
325
- componentRegistry.set(factory, {
326
- name: options?.name,
327
- setup
328
- });
329
- getComponentPlugins().forEach((p) => p.onDefine?.(options?.name, factory, setup));
330
- return factory;
299
+ function isComponent(type) {
300
+ return typeof type === "function" && "__setup" in type;
331
301
  }
332
-
333
- //#endregion
334
- //#region src/jsx-runtime.ts
335
302
  const Fragment = Symbol.for("sigx.Fragment");
336
303
  const Text = Symbol.for("sigx.Text");
337
304
  function normalizeChildren(children) {
338
305
  if (children == null || children === false || children === true) return [];
306
+ if (isComputed(children)) return normalizeChildren(children.value);
339
307
  if (Array.isArray(children)) return children.flatMap((c) => normalizeChildren(c));
340
308
  if (typeof children === "string" || typeof children === "number") return [{
341
309
  type: Text,
@@ -348,64 +316,92 @@ function normalizeChildren(children) {
348
316
  if (children.type) return [children];
349
317
  return [];
350
318
  }
351
- /**
352
- * Check if a type is a sigx component (has __setup)
353
- */
354
- function isComponent$1(type) {
355
- return typeof type === "function" && "__setup" in type;
356
- }
357
- /**
358
- * Create a JSX element - this is the core function called by TSX transpilation
359
- */
360
319
  function jsx(type, props, key) {
361
320
  const processedProps = { ...props || {} };
321
+ const models = {};
322
+ const isComponentType = isComponent(type);
362
323
  if (props) {
363
- for (const propKey in props) if (propKey === "sync") {
364
- let syncBinding = props[propKey];
365
- if (typeof syncBinding === "function") {
366
- const detected = detectAccess(syncBinding);
367
- if (detected) syncBinding = detected;
368
- }
369
- if (Array.isArray(syncBinding) && syncBinding.length === 2) {
370
- const [stateObj, key$1] = syncBinding;
324
+ for (const propKey in props) if (propKey === "model") {
325
+ let modelBinding = props[propKey];
326
+ let tuple = null;
327
+ let updateHandler = null;
328
+ if (isModel(modelBinding)) {
329
+ const [obj, key, handler] = modelBinding.binding;
330
+ tuple = [obj, key];
331
+ updateHandler = handler;
332
+ } else if (typeof modelBinding === "function") {
333
+ const detected = detectAccess(modelBinding);
334
+ if (detected && typeof detected[1] === "string") tuple = detected;
335
+ } else if (Array.isArray(modelBinding) && modelBinding.length === 2 && typeof modelBinding[1] === "string") tuple = modelBinding;
336
+ if (tuple) {
337
+ const [stateObj, stateKey] = tuple;
371
338
  let handled = false;
372
- const platformProcessor = getPlatformSyncProcessor();
373
- if (typeof type === "string" && platformProcessor) handled = platformProcessor(type, processedProps, [stateObj, key$1], props);
374
- if (!handled) {
375
- processedProps.value = stateObj[key$1];
376
- const existingHandler = processedProps["onUpdate:value"];
377
- processedProps["onUpdate:value"] = (v) => {
378
- stateObj[key$1] = v;
339
+ if (!updateHandler) {
340
+ const existingHandler = processedProps["onUpdate:modelValue"];
341
+ updateHandler = (v) => {
342
+ const customHandler = stateObj[`onUpdate:${stateKey}`];
343
+ if (typeof customHandler === "function") customHandler(v);
344
+ else stateObj[stateKey] = v;
379
345
  if (existingHandler) existingHandler(v);
380
346
  };
381
347
  }
382
- delete processedProps.sync;
348
+ const platformProcessor = getPlatformModelProcessor();
349
+ if (typeof type === "string" && platformProcessor) handled = platformProcessor(type, processedProps, tuple, props);
350
+ if (isComponentType) {
351
+ models.model = createModel(tuple, updateHandler);
352
+ processedProps["onUpdate:modelValue"] = updateHandler;
353
+ } else if (!handled) {
354
+ processedProps.modelValue = stateObj[stateKey];
355
+ processedProps["onUpdate:modelValue"] = updateHandler;
356
+ }
357
+ delete processedProps.model;
383
358
  }
384
- } else if (propKey.startsWith("sync:")) {
385
- const syncBinding = props[propKey];
386
- if (Array.isArray(syncBinding) && syncBinding.length === 2) {
387
- const [stateObj, key$1] = syncBinding;
388
- const name = propKey.slice(5);
389
- processedProps[name] = stateObj[key$1];
359
+ } else if (propKey.startsWith("model:")) {
360
+ let modelBinding = props[propKey];
361
+ const name = propKey.slice(6);
362
+ let tuple = null;
363
+ let updateHandler = null;
364
+ if (isModel(modelBinding)) {
365
+ const [obj, key, handler] = modelBinding.binding;
366
+ tuple = [obj, key];
367
+ updateHandler = handler;
368
+ } else if (typeof modelBinding === "function") {
369
+ const detected = detectAccess(modelBinding);
370
+ if (detected && typeof detected[1] === "string") tuple = detected;
371
+ } else if (Array.isArray(modelBinding) && modelBinding.length === 2 && typeof modelBinding[1] === "string") tuple = modelBinding;
372
+ if (tuple) {
373
+ const [stateObj, stateKey] = tuple;
390
374
  const eventName = `onUpdate:${name}`;
391
- const existingHandler = processedProps[eventName];
392
- processedProps[eventName] = (v) => {
393
- stateObj[key$1] = v;
394
- if (existingHandler) existingHandler(v);
395
- };
375
+ if (!updateHandler) {
376
+ const existingHandler = processedProps[eventName];
377
+ updateHandler = (v) => {
378
+ const customHandler = stateObj[`onUpdate:${stateKey}`];
379
+ if (typeof customHandler === "function") customHandler(v);
380
+ else stateObj[stateKey] = v;
381
+ if (existingHandler) existingHandler(v);
382
+ };
383
+ }
384
+ if (isComponentType) {
385
+ models[name] = createModel(tuple, updateHandler);
386
+ processedProps[eventName] = updateHandler;
387
+ } else {
388
+ processedProps[name] = stateObj[stateKey];
389
+ processedProps[eventName] = updateHandler;
390
+ }
396
391
  delete processedProps[propKey];
397
392
  }
398
393
  }
399
394
  }
400
- if (isComponent$1(type)) {
401
- const { children: children$1, ...rest$1 } = processedProps;
395
+ if (Object.keys(models).length > 0) processedProps.$models = models;
396
+ if (isComponent(type)) {
397
+ const { children, ...rest } = processedProps;
402
398
  return {
403
399
  type,
404
400
  props: {
405
- ...rest$1,
406
- children: children$1
401
+ ...rest,
402
+ children
407
403
  },
408
- key: key || rest$1.key || null,
404
+ key: key || rest.key || null,
409
405
  children: [],
410
406
  dom: null
411
407
  };
@@ -420,27 +416,11 @@ function jsx(type, props, key) {
420
416
  dom: null
421
417
  };
422
418
  }
423
- /**
424
- * JSX Factory for fragments
425
- */
426
419
  function jsxs(type, props, key) {
427
420
  return jsx(type, props, key);
428
421
  }
429
422
  const jsxDEV = jsx;
430
-
431
- //#endregion
432
- //#region src/lazy.tsx
433
- /**
434
- * Lazy loading utilities for sigx components.
435
- *
436
- * Provides runtime-only lazy loading with no build dependencies.
437
- * Works with any bundler that supports dynamic import().
438
- */
439
- let currentSuspenseBoundary = null;
440
- /**
441
- * Register a promise with the current Suspense boundary
442
- * @internal
443
- */
423
+ var currentSuspenseBoundary = null;
444
424
  function registerPendingPromise(promise) {
445
425
  const boundary = currentSuspenseBoundary;
446
426
  if (boundary) {
@@ -453,39 +433,12 @@ function registerPendingPromise(promise) {
453
433
  }
454
434
  return false;
455
435
  }
456
- /**
457
- * Create a lazy-loaded component wrapper.
458
- *
459
- * The component will be loaded on first render. Use with `<Suspense>` to show
460
- * a fallback while loading.
461
- *
462
- * @param loader - Function that returns a Promise resolving to the component
463
- * @returns A component factory that loads the real component on demand
464
- *
465
- * @example
466
- * ```tsx
467
- * import { lazy, Suspense } from 'sigx';
468
- *
469
- * // Component will be in a separate chunk
470
- * const HeavyChart = lazy(() => import('./components/HeavyChart'));
471
- *
472
- * // Usage
473
- * <Suspense fallback={<Spinner />}>
474
- * <HeavyChart data={chartData} />
475
- * </Suspense>
476
- *
477
- * // Preload on hover
478
- * <button onMouseEnter={() => HeavyChart.preload()}>
479
- * Show Chart
480
- * </button>
481
- * ```
482
- */
483
436
  function lazy(loader) {
484
437
  let Component = null;
485
438
  let promise = null;
486
439
  let error = null;
487
440
  let state = "pending";
488
- const LazyWrapper = defineComponent((ctx) => {
441
+ const LazyWrapper = component((ctx) => {
489
442
  const loadState = ctx.signal({
490
443
  state,
491
444
  tick: 0
@@ -534,30 +487,7 @@ function lazy(loader) {
534
487
  };
535
488
  return LazyWrapper;
536
489
  }
537
- /**
538
- * Suspense boundary component for handling async loading states.
539
- *
540
- * Wraps lazy-loaded components and shows a fallback while they load.
541
- *
542
- * @example
543
- * ```tsx
544
- * import { lazy, Suspense } from 'sigx';
545
- *
546
- * const LazyDashboard = lazy(() => import('./Dashboard'));
547
- *
548
- * // Basic usage
549
- * <Suspense fallback={<div>Loading...</div>}>
550
- * <LazyDashboard />
551
- * </Suspense>
552
- *
553
- * // With spinner component
554
- * <Suspense fallback={<Spinner size="large" />}>
555
- * <LazyDashboard />
556
- * <LazyCharts />
557
- * </Suspense>
558
- * ```
559
- */
560
- const Suspense = defineComponent((ctx) => {
490
+ const Suspense = component((ctx) => {
561
491
  const { props, slots } = ctx;
562
492
  const state = ctx.signal({
563
493
  isReady: false,
@@ -570,7 +500,7 @@ const Suspense = defineComponent((ctx) => {
570
500
  if (boundary.pending.size === 0) state.isReady = true;
571
501
  }
572
502
  };
573
- ctx.onMount(() => {
503
+ ctx.onMounted(() => {
574
504
  if (boundary.pending.size === 0) state.isReady = true;
575
505
  });
576
506
  return () => {
@@ -605,15 +535,9 @@ const Suspense = defineComponent((ctx) => {
605
535
  }
606
536
  };
607
537
  }, { name: "Suspense" });
608
- /**
609
- * Check if a component is a lazy-loaded component
610
- */
611
538
  function isLazyComponent(component) {
612
539
  return component && component.__lazy === true;
613
540
  }
614
-
615
- //#endregion
616
- //#region src/utils/index.ts
617
541
  var Utils = class {
618
542
  static isPromise(value) {
619
543
  return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
@@ -625,92 +549,29 @@ function guid$1() {
625
549
  return (c == "x" ? r : r & 3 | 8).toString(16);
626
550
  });
627
551
  }
628
-
629
- //#endregion
630
- //#region src/utils/props-accessor.ts
631
- /**
632
- * Creates a props accessor that can be called with defaults or accessed directly.
633
- * After calling with defaults, direct property access uses those defaults.
634
- *
635
- * @example
636
- * ```ts
637
- * // In component setup:
638
- * const props = createPropsAccessor(reactiveProps);
639
- *
640
- * // Set defaults
641
- * props({ count: 0, label: 'Default' });
642
- *
643
- * // Access props (falls back to defaults if not provided)
644
- * const count = props.count;
645
- * ```
646
- */
647
552
  function createPropsAccessor(reactiveProps) {
648
- let defaults = {};
649
- const proxy = new Proxy(function propsAccessor() {}, {
650
- get(_, key) {
553
+ return new Proxy(reactiveProps, {
554
+ get(target, key) {
651
555
  if (typeof key === "symbol") return void 0;
652
- const value = reactiveProps[key];
653
- return value != null ? value : defaults[key];
556
+ return target[key];
654
557
  },
655
- apply(_, __, args) {
656
- if (args[0] && typeof args[0] === "object") defaults = {
657
- ...defaults,
658
- ...args[0]
659
- };
660
- return proxy;
661
- },
662
- has(_, key) {
558
+ has(target, key) {
663
559
  if (typeof key === "symbol") return false;
664
- return key in reactiveProps || key in defaults;
560
+ return key in target;
665
561
  },
666
- ownKeys() {
667
- return [...new Set([...Object.keys(reactiveProps), ...Object.keys(defaults)])];
562
+ ownKeys(target) {
563
+ return Object.keys(target);
668
564
  },
669
- getOwnPropertyDescriptor(_, key) {
565
+ getOwnPropertyDescriptor(target, key) {
670
566
  if (typeof key === "symbol") return void 0;
671
- if (key in reactiveProps || key in defaults) return {
567
+ if (key in target) return {
672
568
  enumerable: true,
673
569
  configurable: true,
674
570
  writable: false
675
571
  };
676
572
  }
677
573
  });
678
- return proxy;
679
574
  }
680
-
681
- //#endregion
682
- //#region src/utils/slots.ts
683
- /**
684
- * Slots system for component children.
685
- * Supports default and named slots with reactivity.
686
- */
687
- /**
688
- * Create slots object from children and slots prop.
689
- * Uses a version signal to trigger re-renders when children change.
690
- *
691
- * Supports named slots via:
692
- * - `slots` prop object (e.g., `slots={{ header: () => <div>...</div> }}`)
693
- * - `slot` prop on children (e.g., `<div slot="header">...</div>`)
694
- *
695
- * @example
696
- * ```tsx
697
- * // Parent component
698
- * <Card slots={{ header: () => <h1>Title</h1> }}>
699
- * <p>Default content</p>
700
- * <span slot="footer">Footer text</span>
701
- * </Card>
702
- *
703
- * // Card component setup
704
- * const slots = createSlots(children, slotsFromProps);
705
- * return () => (
706
- * <div>
707
- * {slots.header()}
708
- * {slots.default()}
709
- * {slots.footer()}
710
- * </div>
711
- * );
712
- * ```
713
- */
714
575
  function createSlots(children, slotsFromProps) {
715
576
  const versionSignal = signal$1({ v: 0 });
716
577
  function extractNamedSlotsFromChildren(c) {
@@ -757,37 +618,6 @@ function createSlots(children, slotsFromProps) {
757
618
  };
758
619
  } });
759
620
  }
760
-
761
- //#endregion
762
- //#region src/utils/normalize.ts
763
- /**
764
- * VNode normalization utilities.
765
- * Converts render results into proper VNode structures.
766
- */
767
- /**
768
- * Normalize render result to a VNode (wrapping arrays in Fragment).
769
- * Handles null, undefined, false, true by returning an empty Text node.
770
- *
771
- * This is used to normalize the return value of component render functions
772
- * into a consistent VNode structure for the renderer to process.
773
- *
774
- * @example
775
- * ```ts
776
- * // Conditional rendering returns null/false
777
- * normalizeSubTree(null) // → empty Text node
778
- * normalizeSubTree(false) // → empty Text node
779
- *
780
- * // Arrays become Fragments
781
- * normalizeSubTree([<A/>, <B/>]) // → Fragment with children
782
- *
783
- * // Primitives become Text nodes
784
- * normalizeSubTree("hello") // → Text node
785
- * normalizeSubTree(42) // → Text node
786
- *
787
- * // VNodes pass through
788
- * normalizeSubTree(<div/>) // → same VNode
789
- * ```
790
- */
791
621
  function normalizeSubTree(result) {
792
622
  if (result == null || result === false || result === true) return {
793
623
  type: Text,
@@ -797,6 +627,7 @@ function normalizeSubTree(result) {
797
627
  dom: null,
798
628
  text: ""
799
629
  };
630
+ if (isComputed(result)) return normalizeSubTree(result.value);
800
631
  if (Array.isArray(result)) return {
801
632
  type: Fragment,
802
633
  props: {},
@@ -814,22 +645,16 @@ function normalizeSubTree(result) {
814
645
  };
815
646
  return result;
816
647
  }
817
-
818
- //#endregion
819
- //#region src/models/index.ts
820
648
  const guid = guid$1;
821
- let InstanceLifetimes = /* @__PURE__ */ function(InstanceLifetimes$1) {
822
- InstanceLifetimes$1[InstanceLifetimes$1["Transient"] = 0] = "Transient";
823
- InstanceLifetimes$1[InstanceLifetimes$1["Scoped"] = 1] = "Scoped";
824
- InstanceLifetimes$1[InstanceLifetimes$1["Singleton"] = 2] = "Singleton";
825
- return InstanceLifetimes$1;
649
+ let InstanceLifetimes = /* @__PURE__ */ function(InstanceLifetimes) {
650
+ InstanceLifetimes[InstanceLifetimes["Transient"] = 0] = "Transient";
651
+ InstanceLifetimes[InstanceLifetimes["Scoped"] = 1] = "Scoped";
652
+ InstanceLifetimes[InstanceLifetimes["Singleton"] = 2] = "Singleton";
653
+ return InstanceLifetimes;
826
654
  }({});
827
655
  function valueOf(obj) {
828
656
  return obj;
829
657
  }
830
-
831
- //#endregion
832
- //#region src/messaging/index.ts
833
658
  function createTopic(options) {
834
659
  let subscribers = [];
835
660
  const publish = (data) => {
@@ -842,7 +667,7 @@ function createTopic(options) {
842
667
  if (idx > -1) subscribers.splice(idx, 1);
843
668
  };
844
669
  try {
845
- onCleanup(unsubscribe);
670
+ onUnmounted(unsubscribe);
846
671
  } catch (e) {}
847
672
  return { unsubscribe };
848
673
  };
@@ -858,72 +683,10 @@ function createTopic(options) {
858
683
  function toSubscriber(topic) {
859
684
  return { subscribe: (handler) => topic.subscribe(handler) };
860
685
  }
861
-
862
- //#endregion
863
- //#region src/di/injectable.ts
864
- function inject(token) {
865
- const ctx = getCurrentInstance();
866
- if (!ctx) return void 0;
867
- let current = ctx;
868
- while (current) {
869
- if (current.provides && current.provides.has(token)) return current.provides.get(token);
870
- current = current.parent;
871
- }
872
- const appContext = getAppContext(ctx);
873
- if (appContext && appContext.provides.has(token)) return appContext.provides.get(token);
874
- }
875
- /**
876
- * Get the app context from the current component context
877
- */
878
- function getAppContext(ctx) {
879
- let current = ctx;
880
- while (current) {
881
- if (current._appContext) return current._appContext;
882
- current = current.parent;
883
- }
884
- return null;
885
- }
886
- /**
887
- * Inject the App instance (useful for plugins)
888
- */
889
- function injectApp() {
890
- return inject(AppContextKey);
891
- }
892
- function provide(token, value) {
893
- const ctx = getCurrentInstance();
894
- if (!ctx) {
895
- console.warn("provide called outside of component setup");
896
- return;
897
- }
898
- if (!ctx.provides) ctx.provides = /* @__PURE__ */ new Map();
899
- ctx.provides.set(token, value);
900
- }
901
- const globalInstances = /* @__PURE__ */ new Map();
902
- function defineInjectable(factory) {
903
- const token = factory;
904
- const useFn = () => {
905
- const injected = inject(token);
906
- if (injected) return injected;
907
- if (!globalInstances.has(token)) globalInstances.set(token, factory());
908
- return globalInstances.get(token);
909
- };
910
- useFn._factory = factory;
911
- useFn._token = token;
912
- return useFn;
913
- }
914
- function defineProvide(useFn) {
915
- const factory = useFn._factory;
916
- const token = useFn._token;
917
- if (!factory || !token) throw new Error("defineProvide must be called with a function created by defineInjectable");
918
- const instance = factory();
919
- provide(token, instance);
920
- return instance;
921
- }
922
-
923
- //#endregion
924
- //#region src/di/factory.ts
925
686
  var SubscriptionHandler = class {
926
- unsubs = [];
687
+ constructor() {
688
+ this.unsubs = [];
689
+ }
927
690
  add(unsub) {
928
691
  this.unsubs.push(unsub);
929
692
  }
@@ -949,7 +712,7 @@ function defineFactory(setup, lifetime, typeIdentifier) {
949
712
  };
950
713
  if (customDispose) customDispose(dispose);
951
714
  else try {
952
- onCleanup(() => dispose());
715
+ onUnmounted(() => dispose());
953
716
  } catch (e) {}
954
717
  return {
955
718
  ...result,
@@ -959,155 +722,59 @@ function defineFactory(setup, lifetime, typeIdentifier) {
959
722
  if (setup.length <= 1) return defineInjectable(() => factoryCreator());
960
723
  return factoryCreator;
961
724
  }
962
-
963
- //#endregion
964
- //#region src/stores/store.ts
965
- function defineStore(name, setup, lifetime = InstanceLifetimes.Scoped) {
966
- return defineFactory((ctxFactory, ...args) => {
967
- const scope = effectScope(true);
968
- let messages = [];
969
- const id = `${name}_${guid()}`;
970
- const result = setup({
971
- ...ctxFactory,
972
- defineState: (state) => {
973
- return defineState(state, id, scope, messages);
974
- },
975
- defineActions: (actions) => {
976
- return defineActions(actions, id, messages);
977
- }
978
- }, ...args);
979
- ctxFactory.onDeactivated(() => {
980
- scope.stop();
981
- messages?.forEach((m) => m.destroy());
982
- messages = null;
983
- });
984
- if (!result.name) result.name = id;
985
- return result;
986
- }, lifetime);
725
+ const CLIENT_DIRECTIVE_PREFIX = "client:";
726
+ const CLIENT_DIRECTIVES = [
727
+ "client:load",
728
+ "client:idle",
729
+ "client:visible",
730
+ "client:media",
731
+ "client:only"
732
+ ];
733
+ function filterClientDirectives(props) {
734
+ const filtered = {};
735
+ for (const key in props) if (!key.startsWith("client:")) filtered[key] = props[key];
736
+ return filtered;
987
737
  }
988
- function defineActions(actions, storeInstanceName, messages) {
989
- const events = {};
990
- const namespace = `${storeInstanceName}.actions.${guid()}`;
991
- const onDispatching = {};
992
- const onDispatched = {};
993
- const onFailure = {};
994
- const result = {
995
- onDispatching,
996
- onDispatched,
997
- onFailure
738
+ function getHydrationDirective(props) {
739
+ if (props["client:load"] !== void 0) return { strategy: "load" };
740
+ if (props["client:idle"] !== void 0) return { strategy: "idle" };
741
+ if (props["client:visible"] !== void 0) return { strategy: "visible" };
742
+ if (props["client:only"] !== void 0) return { strategy: "only" };
743
+ if (props["client:media"] !== void 0) return {
744
+ strategy: "media",
745
+ media: props["client:media"]
998
746
  };
999
- function getEvent(actionName, type) {
1000
- const name = `${actionName}.${type}`;
1001
- if (!events[name]) {
1002
- events[name] = createTopic({
1003
- namespace,
1004
- name
1005
- });
1006
- messages.push(events[name]);
1007
- }
1008
- return events[name];
1009
- }
1010
- Object.keys(actions).forEach((actionName) => {
1011
- onDispatching[actionName] = { subscribe: (fn) => {
1012
- return getEvent(actionName, "onDispatching").subscribe(function() {
1013
- fn.apply(this, arguments[0]);
1014
- });
1015
- } };
1016
- onDispatched[actionName] = { subscribe: (fn) => {
1017
- return getEvent(actionName, "onDispatched").subscribe(function() {
1018
- const msg = arguments[0];
1019
- const allArguments = [msg.result].concat(Array.from(msg.args));
1020
- fn.apply(this, allArguments);
1021
- });
1022
- } };
1023
- onFailure[actionName] = { subscribe: (fn) => {
1024
- return getEvent(actionName, "onFailure").subscribe(function() {
1025
- const msg = arguments[0];
1026
- const allArguments = [msg.reason].concat(Array.from(msg.args));
1027
- fn.apply(this, allArguments);
1028
- });
1029
- } };
1030
- result[actionName] = function() {
1031
- try {
1032
- const currentArguments = arguments;
1033
- getEvent(actionName, "onDispatching").publish(currentArguments);
1034
- const returnedResult = actions[actionName].apply(this, currentArguments);
1035
- if (Utils.isPromise(returnedResult)) returnedResult.then((result$1) => {
1036
- getEvent(actionName, "onDispatched").publish({
1037
- result: returnedResult,
1038
- args: currentArguments
1039
- });
1040
- });
1041
- else getEvent(actionName, "onDispatched").publish({
1042
- result: returnedResult,
1043
- args: currentArguments
1044
- });
1045
- return returnedResult;
1046
- } catch (err) {
1047
- console.error(err);
1048
- getEvent(actionName, "onFailure").publish({
1049
- reason: err,
1050
- args: arguments
1051
- });
1052
- }
1053
- };
1054
- });
1055
- return result;
747
+ return null;
1056
748
  }
1057
- function defineState(value, storeInstanceName, scope, messages) {
1058
- const state = signal$1(value);
1059
- const events = {};
1060
- const mutate = {};
1061
- function initProperty(key) {
1062
- scope.run(() => {
1063
- watch(() => state[key], (newValue) => {
1064
- triggerEvent(key, newValue);
1065
- }, {
1066
- deep: true,
1067
- immediate: true
1068
- });
1069
- });
1070
- mutate[key] = (val) => {
1071
- try {
1072
- let newValue;
1073
- if (typeof val === "function") newValue = val(state[key]);
1074
- else newValue = val;
1075
- state[key] = newValue;
1076
- } catch (err) {
1077
- console.error(err);
1078
- }
1079
- };
1080
- const eventKey = `onMutated${key.charAt(0).toUpperCase()}${key.slice(1)}`;
1081
- if (!events[eventKey]) {
1082
- const topic = createTopic({
1083
- namespace: `${storeInstanceName}.events`,
1084
- name: eventKey
1085
- });
1086
- events[eventKey] = topic;
1087
- messages.push(topic);
1088
- }
1089
- }
1090
- function triggerEvent(name, value$1) {
1091
- const keyString = name;
1092
- events[`onMutated${keyString.charAt(0).toUpperCase()}${keyString.slice(1)}`]?.publish(value$1);
749
+ function hasClientDirective(props) {
750
+ for (const key in props) if (key.startsWith("client:")) return true;
751
+ return false;
752
+ }
753
+ function serializeProps(props) {
754
+ const filtered = filterClientDirectives(props);
755
+ const result = {};
756
+ let hasProps = false;
757
+ for (const key in filtered) {
758
+ const value = filtered[key];
759
+ if (key === "children" || key === "key" || key === "ref" || key === "slots") continue;
760
+ if (typeof value === "function") continue;
761
+ if (typeof value === "symbol") continue;
762
+ if (value === void 0) continue;
763
+ if (key.startsWith("on") && key.length > 2 && key[2] === key[2].toUpperCase()) continue;
764
+ try {
765
+ JSON.stringify(value);
766
+ result[key] = value;
767
+ hasProps = true;
768
+ } catch {}
1093
769
  }
1094
- if (value) Object.keys(value).forEach((key) => {
1095
- initProperty(key);
1096
- });
1097
- return {
1098
- state,
1099
- events,
1100
- mutate
1101
- };
770
+ return hasProps ? result : void 0;
1102
771
  }
1103
-
1104
- //#endregion
1105
- //#region src/renderer.ts
1106
- /**
1107
- * Check if a vnode type is a component (has __setup)
1108
- */
1109
- function isComponent(type) {
1110
- return typeof type === "function" && "__setup" in type;
772
+ function createEmit(reactiveProps) {
773
+ return (event, ...args) => {
774
+ const eventName = `on${event[0].toUpperCase() + event.slice(1)}`;
775
+ const handler = ("value" in reactiveProps ? reactiveProps.value : reactiveProps)?.[eventName];
776
+ if (handler && typeof handler === "function") handler(...args);
777
+ };
1111
778
  }
1112
779
  function createRenderer(options) {
1113
780
  const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options;
@@ -1141,7 +808,72 @@ function createRenderer(options) {
1141
808
  container._vnode = null;
1142
809
  }
1143
810
  }
1144
- function mount(vnode, container, before = null) {
811
+ const svgTags = new Set([
812
+ "svg",
813
+ "animate",
814
+ "animateMotion",
815
+ "animateTransform",
816
+ "circle",
817
+ "clipPath",
818
+ "defs",
819
+ "desc",
820
+ "ellipse",
821
+ "feBlend",
822
+ "feColorMatrix",
823
+ "feComponentTransfer",
824
+ "feComposite",
825
+ "feConvolveMatrix",
826
+ "feDiffuseLighting",
827
+ "feDisplacementMap",
828
+ "feDistantLight",
829
+ "feDropShadow",
830
+ "feFlood",
831
+ "feFuncA",
832
+ "feFuncB",
833
+ "feFuncG",
834
+ "feFuncR",
835
+ "feGaussianBlur",
836
+ "feImage",
837
+ "feMerge",
838
+ "feMergeNode",
839
+ "feMorphology",
840
+ "feOffset",
841
+ "fePointLight",
842
+ "feSpecularLighting",
843
+ "feSpotLight",
844
+ "feTile",
845
+ "feTurbulence",
846
+ "filter",
847
+ "foreignObject",
848
+ "g",
849
+ "image",
850
+ "line",
851
+ "linearGradient",
852
+ "marker",
853
+ "mask",
854
+ "metadata",
855
+ "mpath",
856
+ "path",
857
+ "pattern",
858
+ "polygon",
859
+ "polyline",
860
+ "radialGradient",
861
+ "rect",
862
+ "set",
863
+ "stop",
864
+ "switch",
865
+ "symbol",
866
+ "text",
867
+ "textPath",
868
+ "title",
869
+ "tspan",
870
+ "use",
871
+ "view"
872
+ ]);
873
+ function isSvgTag(tag) {
874
+ return svgTags.has(tag);
875
+ }
876
+ function mount(vnode, container, before = null, parentIsSVG = false) {
1145
877
  if (vnode == null || vnode === false || vnode === true) return;
1146
878
  if (vnode.type === Text) {
1147
879
  const node = hostCreateText(String(vnode.text));
@@ -1154,26 +886,29 @@ function createRenderer(options) {
1154
886
  const anchor = hostCreateComment("");
1155
887
  vnode.dom = anchor;
1156
888
  hostInsert(anchor, container, before);
1157
- if (vnode.children) vnode.children.forEach((child) => mount(child, container, anchor));
889
+ if (vnode.children) vnode.children.forEach((child) => mount(child, container, anchor, parentIsSVG));
1158
890
  return;
1159
891
  }
1160
892
  if (isComponent(vnode.type)) {
1161
893
  mountComponent(vnode, container, before, vnode.type.__setup);
1162
894
  return;
1163
895
  }
1164
- const element = hostCreateElement(vnode.type);
896
+ const tag = vnode.type;
897
+ const isSVG = tag === "svg" || parentIsSVG && tag !== "foreignObject";
898
+ const element = hostCreateElement(tag, isSVG);
1165
899
  vnode.dom = element;
1166
900
  element.__vnode = vnode;
1167
901
  if (vnode.props) {
1168
- for (const key in vnode.props) if (key !== "children" && key !== "key" && key !== "ref") hostPatchProp(element, key, null, vnode.props[key]);
1169
- if (vnode.props.ref) {
902
+ for (const key in vnode.props) if (key !== "children" && key !== "key" && key !== "ref") hostPatchProp(element, key, null, vnode.props[key], isSVG);
903
+ if (vnode.props.ref) untrack(() => {
1170
904
  if (typeof vnode.props.ref === "function") vnode.props.ref(element);
1171
905
  else if (typeof vnode.props.ref === "object") vnode.props.ref.current = element;
1172
- }
906
+ });
1173
907
  }
908
+ const childIsSVG = isSVG && tag !== "foreignObject";
1174
909
  if (vnode.children) vnode.children.forEach((child) => {
1175
910
  child.parent = vnode;
1176
- mount(child, element);
911
+ mount(child, element, null, childIsSVG);
1177
912
  });
1178
913
  hostInsert(element, container, before);
1179
914
  }
@@ -1185,10 +920,10 @@ function createRenderer(options) {
1185
920
  const subTree = internalVNode._subTree;
1186
921
  if (subTree) unmount(subTree, container);
1187
922
  if (vnode.dom) hostRemove(vnode.dom);
1188
- if (vnode.props?.ref) {
923
+ if (vnode.props?.ref) untrack(() => {
1189
924
  if (typeof vnode.props.ref === "function") vnode.props.ref(null);
1190
925
  else if (typeof vnode.props.ref === "object") vnode.props.ref.current = null;
1191
- }
926
+ });
1192
927
  return;
1193
928
  }
1194
929
  if (vnode.type === Fragment) {
@@ -1196,10 +931,10 @@ function createRenderer(options) {
1196
931
  if (vnode.dom) hostRemove(vnode.dom);
1197
932
  return;
1198
933
  }
1199
- if (vnode.props?.ref) {
934
+ if (vnode.props?.ref) untrack(() => {
1200
935
  if (typeof vnode.props.ref === "function") vnode.props.ref(null);
1201
936
  else if (vnode.props.ref && typeof vnode.props.ref === "object") vnode.props.ref.current = null;
1202
- }
937
+ });
1203
938
  if (vnode.children && vnode.children.length > 0) vnode.children.forEach((child) => unmount(child, vnode.dom));
1204
939
  if (vnode.dom) hostRemove(vnode.dom);
1205
940
  }
@@ -1207,7 +942,7 @@ function createRenderer(options) {
1207
942
  if (oldVNode === newVNode) return;
1208
943
  if (!isSameVNode(oldVNode, newVNode)) {
1209
944
  const parent = hostParentNode(oldVNode.dom) || container;
1210
- const nextSibling = hostNextSibling(oldVNode.dom);
945
+ const nextSibling = oldVNode.dom ? hostNextSibling(oldVNode.dom) : null;
1211
946
  unmount(oldVNode, parent);
1212
947
  mount(newVNode, parent, nextSibling);
1213
948
  return;
@@ -1222,12 +957,25 @@ function createRenderer(options) {
1222
957
  const props = oldInternal._componentProps;
1223
958
  newInternal._componentProps = props;
1224
959
  if (props) {
1225
- const newProps$1 = newVNode.props || {};
960
+ const newProps = newVNode.props || {};
961
+ const newModels = newVNode.props?.$models || {};
1226
962
  untrack(() => {
1227
- for (const key in newProps$1) if (key !== "children" && key !== "key" && key !== "ref") {
1228
- if (props[key] !== newProps$1[key]) props[key] = newProps$1[key];
963
+ for (const key in newProps) if (key !== "children" && key !== "key" && key !== "ref" && key !== "$models") {
964
+ if (props[key] !== newProps[key]) props[key] = newProps[key];
965
+ }
966
+ for (const modelKey in newModels) {
967
+ const newModel = newModels[modelKey];
968
+ const oldModel = props[modelKey];
969
+ if (isModel(newModel)) {
970
+ if (isModel(oldModel)) {
971
+ const [newObj, newKey] = newModel.binding;
972
+ const [oldObj, oldKey] = oldModel.binding;
973
+ if (newObj === oldObj && newKey === oldKey) continue;
974
+ }
975
+ props[modelKey] = newModel;
976
+ }
1229
977
  }
1230
- for (const key in props) if (!(key in newProps$1) && key !== "children" && key !== "key" && key !== "ref") delete props[key];
978
+ for (const key in props) if (!(key in newProps) && !(key in newModels) && key !== "children" && key !== "key" && key !== "ref" && key !== "$models") delete props[key];
1231
979
  });
1232
980
  }
1233
981
  const slotsRef = oldInternal._slots;
@@ -1255,27 +1003,43 @@ function createRenderer(options) {
1255
1003
  return;
1256
1004
  }
1257
1005
  if (newVNode.type === Fragment) {
1258
- patchChildren(oldVNode, newVNode, container);
1006
+ patchChildren(oldVNode, newVNode, container, false);
1259
1007
  return;
1260
1008
  }
1261
1009
  const element = newVNode.dom = oldVNode.dom;
1010
+ if (!element) {
1011
+ mount(newVNode, container);
1012
+ return;
1013
+ }
1014
+ const tag = newVNode.type;
1015
+ const isSVG = tag === "svg" || isSvgTag(tag);
1262
1016
  const oldProps = oldVNode.props || {};
1263
1017
  const newProps = newVNode.props || {};
1264
- for (const key in oldProps) if (!(key in newProps) && key !== "children" && key !== "key" && key !== "ref") hostPatchProp(element, key, oldProps[key], null);
1018
+ for (const key in oldProps) if (!(key in newProps) && key !== "children" && key !== "key" && key !== "ref") hostPatchProp(element, key, oldProps[key], null, isSVG);
1265
1019
  for (const key in newProps) {
1266
1020
  const oldValue = oldProps[key];
1267
1021
  const newValue = newProps[key];
1268
- if (key !== "children" && key !== "key" && key !== "ref" && oldValue !== newValue) hostPatchProp(element, key, oldValue, newValue);
1022
+ if (key !== "children" && key !== "key" && key !== "ref" && oldValue !== newValue) hostPatchProp(element, key, oldValue, newValue, isSVG);
1269
1023
  }
1270
- patchChildren(oldVNode, newVNode, element);
1024
+ patchChildren(oldVNode, newVNode, element, isSVG && tag !== "foreignObject");
1271
1025
  }
1272
- function patchChildren(oldVNode, newVNode, container) {
1026
+ function patchChildren(oldVNode, newVNode, container, parentIsSVG = false) {
1273
1027
  const oldChildren = oldVNode.children;
1274
1028
  const newChildren = newVNode.children;
1275
1029
  newChildren.forEach((c) => c.parent = newVNode);
1276
- reconcileChildrenArray(container, oldChildren, newChildren);
1030
+ reconcileChildrenArray(container, oldChildren, newChildren, parentIsSVG);
1277
1031
  }
1278
- function reconcileChildrenArray(parent, oldChildren, newChildren) {
1032
+ function checkDuplicateKeys(children) {
1033
+ if (process.env.NODE_ENV === "production") return;
1034
+ const seenKeys = /* @__PURE__ */ new Set();
1035
+ for (const child of children) if (child?.key != null) {
1036
+ const keyStr = String(child.key);
1037
+ if (seenKeys.has(keyStr)) console.warn(`[SignalX] Duplicate key "${child.key}" detected in list. Keys should be unique among siblings to ensure correct reconciliation. This may cause unexpected behavior when items are reordered, added, or removed.`);
1038
+ seenKeys.add(keyStr);
1039
+ }
1040
+ }
1041
+ function reconcileChildrenArray(parent, oldChildren, newChildren, parentIsSVG = false) {
1042
+ if (process.env.NODE_ENV !== "production") checkDuplicateKeys(newChildren);
1279
1043
  let oldStartIdx = 0;
1280
1044
  let oldEndIdx = oldChildren.length - 1;
1281
1045
  let oldStartVNode = oldChildren[0];
@@ -1317,13 +1081,13 @@ function createRenderer(options) {
1317
1081
  patch(vnodeToMove, newStartVNode, parent);
1318
1082
  oldChildren[idxInOld] = void 0;
1319
1083
  if (vnodeToMove.dom && oldStartVNode.dom) hostInsert(vnodeToMove.dom, parent, oldStartVNode.dom);
1320
- } else mount(newStartVNode, parent, oldStartVNode.dom);
1084
+ } else mount(newStartVNode, parent, oldStartVNode.dom, parentIsSVG);
1321
1085
  newStartVNode = newChildren[++newStartIdx];
1322
1086
  }
1323
1087
  if (oldStartIdx > oldEndIdx) {
1324
1088
  if (newStartIdx <= newEndIdx) {
1325
1089
  const anchor = newChildren[newEndIdx + 1] == null ? null : newChildren[newEndIdx + 1].dom;
1326
- for (let i = newStartIdx; i <= newEndIdx; i++) mount(newChildren[i], parent, anchor);
1090
+ for (let i = newStartIdx; i <= newEndIdx; i++) mount(newChildren[i], parent, anchor, parentIsSVG);
1327
1091
  }
1328
1092
  } else if (newStartIdx > newEndIdx) {
1329
1093
  for (let i = oldStartIdx; i <= oldEndIdx; i++) if (oldChildren[i]) unmount(oldChildren[i], parent);
@@ -1340,7 +1104,11 @@ function createRenderer(options) {
1340
1104
  const map = /* @__PURE__ */ new Map();
1341
1105
  for (let i = beginIdx; i <= endIdx; i++) {
1342
1106
  const key = children[i]?.key;
1343
- if (key != null) map.set(String(key), i);
1107
+ if (key != null) {
1108
+ const keyStr = String(key);
1109
+ if (process.env.NODE_ENV !== "production" && map.has(keyStr)) console.warn(`[SignalX] Duplicate key "${key}" detected in list. Keys should be unique among siblings to ensure correct reconciliation. This may cause unexpected behavior when items are reordered, added, or removed.`);
1110
+ map.set(keyStr, i);
1111
+ }
1344
1112
  }
1345
1113
  return map;
1346
1114
  }
@@ -1355,14 +1123,21 @@ function createRenderer(options) {
1355
1123
  hostInsert(anchor, container, before);
1356
1124
  let exposed = null;
1357
1125
  let exposeCalled = false;
1358
- const { children, slots: slotsFromProps, ...propsData } = vnode.props || {};
1359
- const reactiveProps = signal$1(propsData);
1126
+ const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = vnode.props || {};
1127
+ const propsWithModels = { ...propsData };
1128
+ if (modelsData) for (const modelKey in modelsData) {
1129
+ const modelValue = modelsData[modelKey];
1130
+ if (isModel(modelValue)) propsWithModels[modelKey] = modelValue;
1131
+ }
1132
+ const reactiveProps = signal$1(propsWithModels);
1360
1133
  const internalVNode = vnode;
1361
1134
  internalVNode._componentProps = reactiveProps;
1362
1135
  const slots = createSlots(children, slotsFromProps);
1363
1136
  internalVNode._slots = slots;
1137
+ const createdHooks = [];
1364
1138
  const mountHooks = [];
1365
- const cleanupHooks = [];
1139
+ const updatedHooks = [];
1140
+ const unmountHooks = [];
1366
1141
  const parentInstance = getCurrentInstance();
1367
1142
  const componentName = vnode.type.__name;
1368
1143
  const ctx = {
@@ -1370,16 +1145,19 @@ function createRenderer(options) {
1370
1145
  signal: signal$1,
1371
1146
  props: createPropsAccessor(reactiveProps),
1372
1147
  slots,
1373
- emit: (event, ...args) => {
1374
- const handler = reactiveProps[`on${event[0].toUpperCase() + event.slice(1)}`];
1375
- if (handler && typeof handler === "function") handler(...args);
1376
- },
1148
+ emit: createEmit(reactiveProps),
1377
1149
  parent: parentInstance,
1378
- onMount: (fn) => {
1150
+ onMounted: (fn) => {
1379
1151
  mountHooks.push(fn);
1380
1152
  },
1381
- onCleanup: (fn) => {
1382
- cleanupHooks.push(fn);
1153
+ onUnmounted: (fn) => {
1154
+ unmountHooks.push(fn);
1155
+ },
1156
+ onCreated: (fn) => {
1157
+ createdHooks.push(fn);
1158
+ },
1159
+ onUpdated: (fn) => {
1160
+ updatedHooks.push(fn);
1383
1161
  },
1384
1162
  expose: (exposedValue) => {
1385
1163
  exposed = exposedValue;
@@ -1390,7 +1168,7 @@ function createRenderer(options) {
1390
1168
  };
1391
1169
  applyContextExtensions(ctx);
1392
1170
  ctx.__name = componentName;
1393
- if (currentAppContext) ctx._appContext = currentAppContext;
1171
+ if (!parentInstance && currentAppContext) provideAppContext(ctx, currentAppContext);
1394
1172
  const componentInstance = {
1395
1173
  name: componentName,
1396
1174
  ctx,
@@ -1400,9 +1178,10 @@ function createRenderer(options) {
1400
1178
  let renderFn;
1401
1179
  try {
1402
1180
  const setupResult = setup(ctx);
1403
- if (setupResult && typeof setupResult.then === "function") throw new Error(`Async setup in component "${componentName}" is only supported during SSR. On the client, use pre-loaded data from hydration or fetch in onMount.`);
1181
+ if (setupResult && typeof setupResult.then === "function") throw new Error(`Async setup in component "${componentName}" is only supported during SSR. On the client, use pre-loaded data from hydration or fetch in onMounted.`);
1404
1182
  renderFn = setupResult;
1405
1183
  notifyComponentCreated(currentAppContext, componentInstance);
1184
+ createdHooks.forEach((hook) => hook());
1406
1185
  } catch (err) {
1407
1186
  if (!handleComponentError(currentAppContext, err, componentInstance, "setup")) throw err;
1408
1187
  } finally {
@@ -1410,8 +1189,10 @@ function createRenderer(options) {
1410
1189
  }
1411
1190
  if (vnode.props?.ref) {
1412
1191
  const refValue = exposeCalled ? exposed : null;
1413
- if (typeof vnode.props.ref === "function") vnode.props.ref(refValue);
1414
- else if (vnode.props.ref && typeof vnode.props.ref === "object") vnode.props.ref.current = refValue;
1192
+ untrack(() => {
1193
+ if (typeof vnode.props.ref === "function") vnode.props.ref(refValue);
1194
+ else if (vnode.props.ref && typeof vnode.props.ref === "object") vnode.props.ref.current = refValue;
1195
+ });
1415
1196
  }
1416
1197
  if (renderFn) {
1417
1198
  ctx.renderFn = renderFn;
@@ -1425,6 +1206,7 @@ function createRenderer(options) {
1425
1206
  if (prevSubTree) {
1426
1207
  patch(prevSubTree, subTree, container);
1427
1208
  notifyComponentUpdated(currentAppContext, componentInstance);
1209
+ updatedHooks.forEach((hook) => hook());
1428
1210
  } else mount(subTree, container, anchor);
1429
1211
  internalVNode._subTree = subTree;
1430
1212
  } catch (err) {
@@ -1443,7 +1225,7 @@ function createRenderer(options) {
1443
1225
  notifyComponentMounted(currentAppContext, componentInstance);
1444
1226
  vnode.cleanup = () => {
1445
1227
  notifyComponentUnmounted(currentAppContext, componentInstance);
1446
- cleanupHooks.forEach((hook) => hook(mountCtx));
1228
+ unmountHooks.forEach((hook) => hook(mountCtx));
1447
1229
  };
1448
1230
  }
1449
1231
  return {
@@ -1451,23 +1233,9 @@ function createRenderer(options) {
1451
1233
  patch,
1452
1234
  mount,
1453
1235
  unmount,
1454
- mountComponent,
1455
- createApp: (rootComponent) => {
1456
- return { mount(selectorOrContainer) {
1457
- let container = null;
1458
- if (typeof selectorOrContainer === "string") {
1459
- if (options.querySelector) container = options.querySelector(selectorOrContainer);
1460
- } else container = selectorOrContainer;
1461
- if (!container) {
1462
- console.warn(`Container not found: ${selectorOrContainer}`);
1463
- return;
1464
- }
1465
- render(rootComponent, container);
1466
- } };
1467
- }
1236
+ mountComponent
1468
1237
  };
1469
1238
  }
1239
+ export { CLIENT_DIRECTIVES, CLIENT_DIRECTIVE_PREFIX, Fragment, InstanceLifetimes, SubscriptionHandler, Suspense, Text, Utils, applyContextExtensions, component, compound, createEmit, createModel, createModelFromBinding, createPropsAccessor, createPropsProxy, createRenderer, createSlots, createTopic, defineApp, defineFactory, defineInjectable, defineProvide, filterClientDirectives, getAppContextToken, getComponentMeta, getComponentPlugins, getCurrentInstance, getDefaultMount, getHydrationDirective, getModelSymbol, getPlatformModelProcessor, guid, handleComponentError, hasClientDirective, isComponent, isLazyComponent, isModel, jsx, jsxDEV, jsxs, lazy, normalizeSubTree, notifyComponentCreated, notifyComponentMounted, notifyComponentUnmounted, notifyComponentUpdated, onCreated, onMounted, onUnmounted, onUpdated, provideAppContext, registerComponentPlugin, registerContextExtension, registerPendingPromise, serializeProps, setCurrentInstance, setDefaultMount, setPlatformModelProcessor, signal, toSubscriber, useAppContext, valueOf };
1470
1240
 
1471
- //#endregion
1472
- export { AppContextKey, Fragment, InstanceLifetimes, SubscriptionHandler, Suspense, Text, Utils, applyContextExtensions, createPropsAccessor, createPropsProxy, createRenderer, createSlots, createTopic, defineApp, defineComponent, defineFactory, defineInjectable, defineProvide, defineStore, getComponentMeta, getComponentPlugins, getCurrentInstance, getDefaultMount, getPlatformSyncProcessor, guid, handleComponentError, inject, injectApp, isLazyComponent, jsx, jsxDEV, jsxs, lazy, normalizeSubTree, notifyComponentCreated, notifyComponentMounted, notifyComponentUnmounted, notifyComponentUpdated, onCleanup, onMount, provide, registerComponentPlugin, registerContextExtension, registerPendingPromise, setCurrentInstance, setDefaultMount, setPlatformSyncProcessor, signal, toSubscriber, valueOf };
1473
1241
  //# sourceMappingURL=index.js.map