@sigx/runtime-dom 0.1.5 → 0.1.7

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.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Portal component for rendering children to a different DOM location.
3
+ *
4
+ * Uses the `moveBefore` API (Chrome 133+) when available for state-preserving
5
+ * DOM moves. Falls back to `insertBefore` for older browsers.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { Portal } from '@sigx/runtime-dom';
10
+ *
11
+ * // Render to document.body (default)
12
+ * <Portal>
13
+ * <div class="modal">Modal content</div>
14
+ * </Portal>
15
+ *
16
+ * // Render to a specific container
17
+ * <Portal to={document.getElementById('modal-root')}>
18
+ * <div class="modal">Modal content</div>
19
+ * </Portal>
20
+ *
21
+ * // Render to a container by selector
22
+ * <Portal to="#modal-root">
23
+ * <div class="modal">Modal content</div>
24
+ * </Portal>
25
+ * ```
26
+ */
27
+ import { DefineProp } from '@sigx/runtime-core';
28
+ /**
29
+ * Check if the browser supports the moveBefore API.
30
+ * moveBefore allows moving DOM nodes without losing state (iframes, videos, focus, etc.)
31
+ */
32
+ export declare function supportsMoveBefore(): boolean;
33
+ /**
34
+ * Move or insert a node into a parent, using moveBefore when available
35
+ * for state-preserving moves.
36
+ *
37
+ * @param parent - The target parent element
38
+ * @param node - The node to move/insert
39
+ * @param anchor - Optional reference node to insert before
40
+ */
41
+ export declare function moveNode(parent: Element, node: Node, anchor?: Node | null): void;
42
+ type PortalProps = DefineProp<'to', string | Element> & DefineProp<'disabled', boolean>;
43
+ /**
44
+ * Portal component - renders children to a different DOM location.
45
+ *
46
+ * Props:
47
+ * - `to` - Target container (Element or CSS selector string). Defaults to document.body.
48
+ * - `disabled` - When true, renders children in place instead of portaling
49
+ * - `children` - Content to render in the portal
50
+ *
51
+ * Features:
52
+ * - Uses `moveBefore` API (Chrome 133+) for state-preserving DOM moves
53
+ * - Preserves iframe content, video playback, focus, and CSS animations
54
+ * - Falls back to `insertBefore` for older browsers
55
+ */
56
+ export declare const Portal: import("@sigx/runtime-core").ComponentFactory<PortalProps, void, {}>;
57
+ export {};
58
+ //# sourceMappingURL=Portal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Portal.d.ts","sourceRoot":"","sources":["../src/Portal.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAa,UAAU,EAA0C,MAAM,oBAAoB,CAAC;AAInG;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACpB,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,IAAI,EACV,MAAM,GAAE,IAAI,GAAG,IAAW,GAC3B,IAAI,CAQN;AAuBD,KAAK,WAAW,GAAG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,UAAU,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAExF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,MAAM,sEA2EG,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * JSX type augmentation for the `show` directive.
3
+ *
4
+ * Adds `use:show` to `DirectiveAttributeExtensions` so that typing `use:`
5
+ * in JSX triggers IntelliSense with `use:show` as a suggestion.
6
+ */
7
+ import type { DirectiveDefinition } from '@sigx/runtime-core';
8
+ declare global {
9
+ namespace JSX {
10
+ interface DirectiveAttributeExtensions {
11
+ /**
12
+ * Toggle element visibility via `display` CSS property.
13
+ *
14
+ * The element stays in the DOM — only its `display` is toggled.
15
+ * Preserves original display value (e.g., `flex`, `grid`).
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // Shorthand — directive resolved automatically:
20
+ * <div use:show={isVisible}>Content</div>
21
+ *
22
+ * // Explicit tuple form:
23
+ * import { show } from 'sigx';
24
+ * <div use:show={[show, isVisible]}>Content</div>
25
+ * ```
26
+ */
27
+ 'use:show'?: boolean | DirectiveDefinition<boolean, HTMLElement> | [DirectiveDefinition<boolean, HTMLElement>, boolean];
28
+ }
29
+ }
30
+ }
31
+ //# sourceMappingURL=show-jsx-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show-jsx-types.d.ts","sourceRoot":"","sources":["../../src/directives/show-jsx-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,GAAG,CAAC;QACV,UAAU,4BAA4B;YAClC;;;;;;;;;;;;;;;eAeG;YACH,UAAU,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;SAC3H;KACJ;CACJ"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Built-in `show` directive — toggles element visibility via `display` CSS property.
3
+ *
4
+ * Unlike conditional rendering (ternary in JSX), `use:show` keeps the element in the DOM
5
+ * and only toggles its `display` style. This is useful when toggling is frequent and you
6
+ * want to preserve element state (e.g., scroll position, input focus).
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * // Shorthand — directive resolved automatically:
11
+ * <div use:show={isVisible}>Content</div>
12
+ *
13
+ * // Explicit tuple form:
14
+ * import { show } from 'sigx';
15
+ * <div use:show={[show, isVisible]}>Content</div>
16
+ * ```
17
+ */
18
+ export declare const show: import("@sigx/runtime-core").DirectiveDefinition<boolean, HTMLElement>;
19
+ //# sourceMappingURL=show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../src/directives/show.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAYH,eAAO,MAAM,IAAI,wEAwBf,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,13 +1,69 @@
1
1
  import './jsx';
2
- import './types.js';
2
+ import './types';
3
+ import './directives/show-jsx-types';
3
4
  import { RendererOptions } from '@sigx/runtime-core';
5
+ import { type DirectiveDefinition } from '@sigx/runtime-core';
6
+ import type { AppContext } from '@sigx/runtime-core';
7
+ /**
8
+ * A directive definition narrowed to DOM elements.
9
+ * Use this type when defining directives for the DOM renderer.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { defineDirective, type DOMDirective } from 'sigx';
14
+ *
15
+ * const tooltip = defineDirective<string, HTMLElement>({
16
+ * mounted(el, { value }) {
17
+ * el.title = value; // el is HTMLElement, fully typed
18
+ * }
19
+ * });
20
+ * ```
21
+ */
22
+ export type DOMDirective<T = any> = DirectiveDefinition<T, HTMLElement>;
23
+ /**
24
+ * Register a built-in directive so it can be used with the shorthand syntax:
25
+ * `<div use:show={value}>` instead of `<div use:show={[show, value]}>`.
26
+ * @internal
27
+ */
28
+ export declare function registerBuiltInDirective(name: string, def: DirectiveDefinition): void;
29
+ /**
30
+ * Look up a registered built-in directive by name.
31
+ * Used by SSR renderer to resolve `use:<name>={value}` shorthand.
32
+ * @internal
33
+ */
34
+ export declare function resolveBuiltInDirective(name: string): DirectiveDefinition | undefined;
35
+ /**
36
+ * Process a `use:*` prop in patchProp.
37
+ * Handles directive created and updated lifecycle hooks.
38
+ * @internal
39
+ */
40
+ declare function patchDirective(el: Element, name: string, prevValue: any, nextValue: any, appContext: AppContext | null): void;
41
+ /**
42
+ * Called after an element is inserted into the DOM.
43
+ * Invokes `mounted` hooks for all directives on the element.
44
+ * @internal
45
+ */
46
+ declare function onElementMounted(el: Element): void;
4
47
  declare function patchProp(dom: Element, key: string, prevValue: any, nextValue: any, isSVG?: boolean): void;
5
48
  declare const nodeOps: RendererOptions<Node, Element>;
6
- export declare const render: import("@sigx/runtime-core").RootRenderFunction<Node, Element>, createApp: (rootComponent: any) => {
7
- mount: (selectorOrContainer: string | Element) => void;
8
- };
49
+ /**
50
+ * Render a SignalX element to a DOM container.
51
+ * Supports both Element references and CSS selectors.
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * import { render } from 'sigx';
56
+ *
57
+ * // Using CSS selector
58
+ * render(<App />, "#app");
59
+ *
60
+ * // Using element reference
61
+ * render(<App />, document.getElementById('app')!);
62
+ * ```
63
+ */
64
+ export declare const render: (element: any, container: Element | string, appContext?: any) => void;
9
65
  export declare const patch: import("@sigx/runtime-core").RendererPatchFn<Node, Element>, mount: import("@sigx/runtime-core").RendererMountFn<Node, Element>, unmount: import("@sigx/runtime-core").RendererUnmountFn<Node, Element>, mountComponent: import("@sigx/runtime-core").RendererMountComponentFn<Node, Element>;
10
- export { patchProp, nodeOps };
66
+ export { patchProp, patchDirective, onElementMounted, nodeOps };
11
67
  /**
12
68
  * Mount function for DOM environments.
13
69
  * Use this with defineApp().mount() to render to the DOM.
@@ -23,4 +79,6 @@ export { patchProp, nodeOps };
23
79
  * ```
24
80
  */
25
81
  export declare const domMount: (component: any, container: HTMLElement | Element | ShadowRoot | string, appContext?: any) => (() => void);
82
+ export { Portal, supportsMoveBefore, moveNode } from './Portal.js';
83
+ export { show } from './directives/show.js';
26
84
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,CAAC;AAEf,OAAO,YAAY,CAAC;AACpB,OAAO,EAAyE,eAAe,EAAyB,MAAM,oBAAoB,CAAC;AAoDnJ,iBAAS,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,OAAO,QAmI5F;AAED,QAAA,MAAM,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,OAAO,CA4B3C,CAAC;AAKF,eAAO,MAAQ,MAAM,kEAAE,SAAS;;CAAa,CAAC;AAG9C,eAAO,MAAQ,KAAK,+DAAE,KAAK,+DAAE,OAAO,iEAAE,cAAc,sEAAa,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAE9B;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,GAAG,EAAE,WAAW,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,EAAE,aAAa,GAAG,KAAG,CAAC,MAAM,IAAI,CAiB9H,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,CAAC;AAEf,OAAO,SAAS,CAAC;AAEjB,OAAO,6BAA6B,CAAC;AACrC,OAAO,EAA0E,eAAe,EAAyB,MAAM,oBAAoB,CAAC;AACpJ,OAAO,EAAe,KAAK,mBAAmB,EAAyB,MAAM,oBAAoB,CAAC;AAClG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,GAAG,GAAG,IAAI,mBAAmB,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AAcxE;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAErF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAErF;AA+BD;;;;GAIG;AACH,iBAAS,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAoEtH;AAED;;;;GAIG;AACH,iBAAS,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAS3C;AA+ID,iBAAS,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,OAAO,QAgL5F;AAED,QAAA,MAAM,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,OAAO,CAkC3C,CAAC;AAIF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,GAAI,SAAS,GAAG,EAAE,WAAW,OAAO,GAAG,MAAM,EAAE,aAAa,GAAG,KAAG,IAUpF,CAAC;AAGF,eAAO,MAAQ,KAAK,+DAAE,KAAK,+DAAE,OAAO,iEAAE,cAAc,sEAAa,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AAEhE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,WAAW,GAAG,EAAE,WAAW,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,EAAE,aAAa,GAAG,KAAG,CAAC,MAAM,IAAI,CAiB9H,CAAC;AAMF,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGnE,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -1,25 +1,184 @@
1
- import { createRenderer, setDefaultMount, setPlatformSyncProcessor } from "@sigx/runtime-core";
2
-
3
- //#region src/index.ts
4
- setPlatformSyncProcessor((type, props, [stateObj, key], originalProps) => {
1
+ import { Fragment, component as component$1, createRenderer, defineDirective, isDirective, jsx, normalizeSubTree, setDefaultMount, setPlatformModelProcessor } from "@sigx/runtime-core";
2
+ import { effect } from "@sigx/reactivity";
3
+ function supportsMoveBefore() {
4
+ return typeof Node !== "undefined" && "moveBefore" in Node.prototype;
5
+ }
6
+ function moveNode(parent, node, anchor = null) {
7
+ if (supportsMoveBefore()) parent.moveBefore(node, anchor);
8
+ else parent.insertBefore(node, anchor);
9
+ }
10
+ function resolveTarget(target) {
11
+ if (target === void 0) return document.body;
12
+ if (typeof target === "string") {
13
+ const resolved = document.querySelector(target);
14
+ if (!resolved) {
15
+ console.warn(`Portal: Target "${target}" not found, falling back to document.body`);
16
+ return document.body;
17
+ }
18
+ return resolved;
19
+ }
20
+ return target;
21
+ }
22
+ const Portal = component$1(({ props, slots, onMounted, onUnmounted }) => {
23
+ let portalContainer = null;
24
+ let mountedVNode = null;
25
+ let cleanupEffect = null;
26
+ onMounted(() => {
27
+ if (props.disabled) return;
28
+ const targetContainer = resolveTarget(props.to);
29
+ portalContainer = document.createElement("div");
30
+ portalContainer.setAttribute("data-sigx-portal", "");
31
+ moveNode(targetContainer, portalContainer);
32
+ cleanupEffect = effect(() => {
33
+ const children = slots.default();
34
+ if (!portalContainer) return;
35
+ const vnode = normalizeSubTree(children);
36
+ if (mountedVNode) patch(mountedVNode, vnode, portalContainer);
37
+ else mount(vnode, portalContainer);
38
+ mountedVNode = vnode;
39
+ });
40
+ });
41
+ onUnmounted(() => {
42
+ if (cleanupEffect) {
43
+ cleanupEffect();
44
+ cleanupEffect = null;
45
+ }
46
+ if (mountedVNode && portalContainer) {
47
+ unmount(mountedVNode, portalContainer);
48
+ mountedVNode = null;
49
+ }
50
+ if (portalContainer && portalContainer.parentNode) portalContainer.parentNode.removeChild(portalContainer);
51
+ portalContainer = null;
52
+ });
53
+ return () => {
54
+ if (props.disabled) return jsx(Fragment, { children: slots.default() });
55
+ return null;
56
+ };
57
+ }, { name: "Portal" });
58
+ var ORIGINAL_DISPLAY = Symbol("sigx.show.originalDisplay");
59
+ const show = defineDirective({
60
+ mounted(el, { value }) {
61
+ const showEl = el;
62
+ const saved = showEl.style.display === "none" ? "" : showEl.style.display;
63
+ showEl[ORIGINAL_DISPLAY] = saved;
64
+ showEl.style.display = value ? saved : "none";
65
+ },
66
+ updated(el, { value, oldValue }) {
67
+ if (value !== oldValue) {
68
+ const showEl = el;
69
+ showEl.style.display = value ? showEl[ORIGINAL_DISPLAY] ?? "" : "none";
70
+ }
71
+ },
72
+ unmounted(el) {
73
+ const showEl = el;
74
+ const original = showEl[ORIGINAL_DISPLAY];
75
+ if (original !== void 0) showEl.style.display = original;
76
+ }
77
+ });
78
+ var builtInDirectives = /* @__PURE__ */ new Map();
79
+ function registerBuiltInDirective(name, def) {
80
+ builtInDirectives.set(name, def);
81
+ }
82
+ function resolveBuiltInDirective(name) {
83
+ return builtInDirectives.get(name);
84
+ }
85
+ var DIRECTIVE_STATE = Symbol.for("sigx.directives");
86
+ function getDirectiveMap(el) {
87
+ let map = el[DIRECTIVE_STATE];
88
+ if (!map) {
89
+ map = /* @__PURE__ */ new Map();
90
+ el[DIRECTIVE_STATE] = map;
91
+ }
92
+ return map;
93
+ }
94
+ function patchDirective(el, name, prevValue, nextValue, appContext) {
95
+ const dirMap = getDirectiveMap(el);
96
+ if (nextValue == null) {
97
+ dirMap.delete(name);
98
+ return;
99
+ }
100
+ let def;
101
+ let value;
102
+ if (isDirective(nextValue)) {
103
+ def = nextValue;
104
+ value = void 0;
105
+ } else if (Array.isArray(nextValue) && nextValue.length >= 1 && isDirective(nextValue[0])) {
106
+ def = nextValue[0];
107
+ value = nextValue[1];
108
+ } else {
109
+ const builtIn = builtInDirectives.get(name);
110
+ if (builtIn) {
111
+ def = builtIn;
112
+ value = nextValue;
113
+ } else {
114
+ const custom = appContext?.directives.get(name);
115
+ if (custom) {
116
+ def = custom;
117
+ value = nextValue;
118
+ } else {
119
+ console.warn(`[sigx] Directive "use:${name}" could not be resolved. Make sure to register it via app.directive('${name}', definition) or pass a directive definition directly.`);
120
+ return;
121
+ }
122
+ }
123
+ }
124
+ const existing = dirMap.get(name);
125
+ if (!existing) {
126
+ const state = {
127
+ def,
128
+ value
129
+ };
130
+ dirMap.set(name, state);
131
+ if (def.created) def.created(el, { value });
132
+ } else {
133
+ const oldValue = existing.value;
134
+ existing.def = def;
135
+ existing.value = value;
136
+ if (def.updated && value !== oldValue) def.updated(el, {
137
+ value,
138
+ oldValue
139
+ });
140
+ }
141
+ }
142
+ function onElementMounted(el) {
143
+ const map = el[DIRECTIVE_STATE];
144
+ if (!map) return;
145
+ for (const [, state] of map) if (state.def.mounted) state.def.mounted(el, { value: state.value });
146
+ }
147
+ function onElementUnmounted(el) {
148
+ const map = el[DIRECTIVE_STATE];
149
+ if (!map) return;
150
+ for (const [, state] of map) {
151
+ if (state.def.unmounted) state.def.unmounted(el, { value: state.value });
152
+ if (state.cleanup) state.cleanup();
153
+ }
154
+ map.clear();
155
+ delete el[DIRECTIVE_STATE];
156
+ }
157
+ var svgNS = "http://www.w3.org/2000/svg";
158
+ setPlatformModelProcessor((type, props, [stateObj, key], originalProps) => {
159
+ const setValue = (v) => {
160
+ const updateHandler = stateObj[`onUpdate:${key}`];
161
+ if (typeof updateHandler === "function") updateHandler(v);
162
+ else stateObj[key] = v;
163
+ };
5
164
  if (type === "input" && originalProps.type === "checkbox") {
6
165
  const val = stateObj[key];
7
166
  if (Array.isArray(val)) {
8
167
  props.checked = val.includes(originalProps.value);
9
- const existingHandler = props["onUpdate:value"];
10
- props["onUpdate:value"] = (checked) => {
168
+ const existingHandler = props["onUpdate:modelValue"];
169
+ props["onUpdate:modelValue"] = (checked) => {
11
170
  const currentVal = originalProps.value;
12
171
  const currentArr = stateObj[key];
13
172
  if (checked) {
14
- if (!currentArr.includes(currentVal)) stateObj[key] = [...currentArr, currentVal];
15
- } else stateObj[key] = currentArr.filter((i) => i !== currentVal);
173
+ if (!currentArr.includes(currentVal)) setValue([...currentArr, currentVal]);
174
+ } else setValue(currentArr.filter((i) => i !== currentVal));
16
175
  if (existingHandler) existingHandler(checked);
17
176
  };
18
177
  } else {
19
178
  props.checked = val;
20
- const existingHandler = props["onUpdate:value"];
21
- props["onUpdate:value"] = (v) => {
22
- stateObj[key] = v;
179
+ const existingHandler = props["onUpdate:modelValue"];
180
+ props["onUpdate:modelValue"] = (v) => {
181
+ setValue(v);
23
182
  if (existingHandler) existingHandler(v);
24
183
  };
25
184
  }
@@ -27,17 +186,46 @@ setPlatformSyncProcessor((type, props, [stateObj, key], originalProps) => {
27
186
  }
28
187
  if (type === "input" && originalProps.type === "radio") {
29
188
  props.checked = stateObj[key] === originalProps.value;
30
- const existingHandler = props["onUpdate:value"];
31
- props["onUpdate:value"] = (checked) => {
32
- if (checked) stateObj[key] = originalProps.value;
189
+ const existingHandler = props["onUpdate:modelValue"];
190
+ props["onUpdate:modelValue"] = (checked) => {
191
+ if (checked) setValue(originalProps.value);
33
192
  if (existingHandler) existingHandler(checked);
34
193
  };
35
194
  return true;
36
195
  }
196
+ if (type === "input") {
197
+ props.value = stateObj[key] ?? "";
198
+ const existingHandler = props["onUpdate:modelValue"];
199
+ props["onUpdate:modelValue"] = (v) => {
200
+ setValue(v);
201
+ if (existingHandler) existingHandler(v);
202
+ };
203
+ return true;
204
+ }
205
+ if (type === "textarea") {
206
+ props.value = stateObj[key] ?? "";
207
+ const existingHandler = props["onUpdate:modelValue"];
208
+ props["onUpdate:modelValue"] = (v) => {
209
+ setValue(v);
210
+ if (existingHandler) existingHandler(v);
211
+ };
212
+ return true;
213
+ }
214
+ if (type === "select") {
215
+ props.value = stateObj[key] ?? "";
216
+ const existingHandler = props["onUpdate:modelValue"];
217
+ props["onUpdate:modelValue"] = (v) => {
218
+ setValue(v);
219
+ if (existingHandler) existingHandler(v);
220
+ };
221
+ return true;
222
+ }
37
223
  return false;
38
224
  });
39
225
  function patchProp(dom, key, prevValue, nextValue, isSVG) {
226
+ if (!dom) return;
40
227
  const tagName = dom.tagName.toLowerCase();
228
+ const isSvgElement = isSVG ?? dom instanceof SVGElement;
41
229
  const oldValue = prevValue;
42
230
  const newValue = nextValue;
43
231
  if (key === "children" || key === "key" || key === "ref") return;
@@ -49,10 +237,10 @@ function patchProp(dom, key, prevValue, nextValue, isSVG) {
49
237
  else el.style[styleKey] = styleObj[styleKey];
50
238
  } else el.style.cssText = String(newValue);
51
239
  } else if (key.startsWith("on")) {
52
- if (key === "onUpdate:value" && (tagName === "input" || tagName === "textarea" || tagName === "select")) {
240
+ if (key === "onUpdate:modelValue" && (tagName === "input" || tagName === "textarea" || tagName === "select")) {
53
241
  const el = dom;
54
242
  if (oldValue) {
55
- const wrapper = oldValue.__sigx_sync_handler;
243
+ const wrapper = oldValue.__sigx_model_handler;
56
244
  if (wrapper) {
57
245
  el.removeEventListener("input", wrapper);
58
246
  el.removeEventListener("change", wrapper);
@@ -68,7 +256,7 @@ function patchProp(dom, key, prevValue, nextValue, isSVG) {
68
256
  else val = target.value;
69
257
  newValue(val);
70
258
  };
71
- newValue.__sigx_sync_handler = handler;
259
+ newValue.__sigx_model_handler = handler;
72
260
  const inputType = dom.type;
73
261
  if (tagName === "select" || tagName === "input" && (inputType === "checkbox" || inputType === "radio")) el.addEventListener("change", handler);
74
262
  else el.addEventListener("input", handler);
@@ -99,11 +287,29 @@ function patchProp(dom, key, prevValue, nextValue, isSVG) {
99
287
  else if (key.startsWith(".")) {
100
288
  const propName = key.slice(1);
101
289
  dom[propName] = newValue;
102
- } else if ((tagName === "input" || tagName === "textarea" || tagName === "select") && (key === "value" || key === "checked")) {
103
- if (tagName === "select" && key === "value") return;
290
+ } else if (key.startsWith("prop:")) {
291
+ const propName = key.slice(5);
292
+ dom[propName] = newValue;
293
+ } else if (isSvgElement) if (key === "innerHTML" || key === "textContent") dom[key] = newValue ?? "";
294
+ else if (key.startsWith("xlink:")) {
295
+ const xlinkNS = "http://www.w3.org/1999/xlink";
296
+ if (newValue == null) dom.removeAttributeNS(xlinkNS, key.slice(6));
297
+ else dom.setAttributeNS(xlinkNS, key, String(newValue));
298
+ } else if (newValue === true) dom.setAttribute(key, "");
299
+ else if (newValue === false || newValue == null) dom.removeAttribute(key);
300
+ else dom.setAttribute(key, String(newValue));
301
+ else if ((tagName === "input" || tagName === "textarea" || tagName === "select") && (key === "value" || key === "checked")) {
302
+ if (tagName === "select" && key === "value") {
303
+ queueMicrotask(() => {
304
+ dom.value = String(newValue ?? "");
305
+ });
306
+ return;
307
+ }
104
308
  if (key === "checked" && tagName === "input") dom.checked = Boolean(newValue);
105
309
  else if (key === "value") dom.value = String(newValue ?? "");
106
- } else if (key in dom) try {
310
+ } else if (key in dom) if (newValue == null) {
311
+ if (dom.hasAttribute?.(key)) dom.removeAttribute(key);
312
+ } else try {
107
313
  dom[key] = newValue;
108
314
  } catch (e) {
109
315
  dom.setAttribute(key, String(newValue));
@@ -113,7 +319,7 @@ function patchProp(dom, key, prevValue, nextValue, isSVG) {
113
319
  else if (newValue === false || newValue == null) dom.removeAttribute(key);
114
320
  else dom.setAttribute(key, String(newValue));
115
321
  }
116
- const nodeOps = {
322
+ var nodeOps = {
117
323
  insert: (child, parent, anchor) => {
118
324
  parent.insertBefore(child, anchor || null);
119
325
  },
@@ -122,6 +328,7 @@ const nodeOps = {
122
328
  if (parent) parent.removeChild(child);
123
329
  },
124
330
  createElement: (tag, isSVG, isCustomizedBuiltIn) => {
331
+ if (isSVG) return document.createElementNS(svgNS, tag);
125
332
  const is = isCustomizedBuiltIn ? { is: isCustomizedBuiltIn } : void 0;
126
333
  return document.createElement(tag, is);
127
334
  },
@@ -138,25 +345,18 @@ const nodeOps = {
138
345
  querySelector: (selector) => document.querySelector(selector),
139
346
  setScopeId: (el, id) => el.setAttribute(id, ""),
140
347
  cloneNode: (node) => node.cloneNode(true),
141
- patchProp
348
+ patchProp,
349
+ patchDirective,
350
+ onElementMounted,
351
+ onElementUnmounted
352
+ };
353
+ var renderer = createRenderer(nodeOps);
354
+ const render = (element, container, appContext) => {
355
+ const target = typeof container === "string" ? document.querySelector(container) : container;
356
+ if (!target) throw new Error(`Render target "${container}" not found.`);
357
+ return renderer.render(element, target, appContext);
142
358
  };
143
- const renderer = createRenderer(nodeOps);
144
- const { render, createApp } = renderer;
145
359
  const { patch, mount, unmount, mountComponent } = renderer;
146
- /**
147
- * Mount function for DOM environments.
148
- * Use this with defineApp().mount() to render to the DOM.
149
- *
150
- * @example
151
- * ```tsx
152
- * import { defineApp } from '@sigx/runtime-core';
153
- * import { domMount } from '@sigx/runtime-dom';
154
- *
155
- * const app = defineApp(<App />);
156
- * app.use(routerPlugin)
157
- * .mount(document.getElementById('app')!, domMount);
158
- * ```
159
- */
160
360
  const domMount = (component, container, appContext) => {
161
361
  const target = typeof container === "string" ? document.querySelector(container) : container;
162
362
  if (!target) throw new Error(`Mount target "${container}" not found.`);
@@ -166,7 +366,7 @@ const domMount = (component, container, appContext) => {
166
366
  };
167
367
  };
168
368
  setDefaultMount(domMount);
369
+ registerBuiltInDirective("show", show);
370
+ export { Portal, domMount, mount, mountComponent, moveNode, nodeOps, onElementMounted, patch, patchDirective, patchProp, registerBuiltInDirective, render, resolveBuiltInDirective, show, supportsMoveBefore, unmount };
169
371
 
170
- //#endregion
171
- export { createApp, domMount, mount, mountComponent, nodeOps, patch, patchProp, render, unmount };
172
372
  //# sourceMappingURL=index.js.map