@shane_il/pulse 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shane-IL
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # Pulse
2
+
3
+ A render-driven UI framework with virtual DOM and immutable stores. Like React, but with no hooks — state stores are first-class citizens and components are pure render functions.
4
+
5
+ ## Why Pulse?
6
+
7
+ - **No hooks.** All state lives in external stores. Components are `(props) => VNode`.
8
+ - **Stores are first-class.** Create, import, and share stores anywhere. They're framework-agnostic.
9
+ - **Render-driven.** Describe what the UI looks like for a given state. Pulse handles the rest.
10
+ - **Built-in routing.** Store-based client-side router — routes are just state.
11
+ - **Tiny.** ~5 KB gzipped. Zero runtime dependencies.
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ npm install pulse-ui
17
+ ```
18
+
19
+ Configure your JSX pragma (jsconfig.json, tsconfig.json, or Babel):
20
+
21
+ ```json
22
+ {
23
+ "compilerOptions": {
24
+ "jsx": "react",
25
+ "jsxFactory": "h",
26
+ "jsxFragmentFactory": "Fragment"
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Example
32
+
33
+ ```jsx
34
+ import { h, createStore, connect, render } from 'pulse-ui';
35
+
36
+ // 1. Create a store
37
+ const counterStore = createStore({
38
+ state: { count: 0 },
39
+ actions: {
40
+ increment: (state) => ({ ...state, count: state.count + 1 }),
41
+ decrement: (state) => ({ ...state, count: state.count - 1 }),
42
+ set: (state, value) => ({ ...state, count: value }),
43
+ },
44
+ });
45
+
46
+ // 2. Write a pure component
47
+ function Counter({ count }) {
48
+ return (
49
+ <div>
50
+ <h1>{count}</h1>
51
+ <button onClick={() => counterStore.dispatch('increment')}>+</button>
52
+ <button onClick={() => counterStore.dispatch('decrement')}>-</button>
53
+ </div>
54
+ );
55
+ }
56
+
57
+ // 3. Connect it to the store
58
+ const ConnectedCounter = connect({
59
+ count: counterStore.select((state) => state.count),
60
+ })(Counter);
61
+
62
+ // 4. Render
63
+ render(<ConnectedCounter />, document.getElementById('app'));
64
+ ```
65
+
66
+ ## API
67
+
68
+ ### `createStore({ state, actions })`
69
+
70
+ Creates an immutable state store.
71
+
72
+ ```js
73
+ const store = createStore({
74
+ state: { count: 0 },
75
+ actions: {
76
+ increment: (state) => ({ ...state, count: state.count + 1 }),
77
+ set: (state, value) => ({ ...state, count: value }),
78
+ },
79
+ });
80
+
81
+ store.getState(); // { count: 0 }
82
+ store.dispatch('increment'); // state is now { count: 1 }
83
+ store.dispatch('set', 42); // state is now { count: 42 }
84
+
85
+ const unsub = store.subscribe((newState) => {
86
+ console.log('State changed:', newState);
87
+ });
88
+ unsub(); // unsubscribe
89
+ ```
90
+
91
+ Actions are pure functions: `(state, payload) => newState`. If an action returns the same reference (`===`), subscribers are not notified.
92
+
93
+ Stores are standalone — they work outside of Pulse and can be shared across your app.
94
+
95
+ ### `connect(bindings, lifecycle?)(Component)`
96
+
97
+ Connects a store's state to a component via selectors, with optional lifecycle callbacks.
98
+
99
+ ```js
100
+ const Connected = connect({
101
+ count: counterStore.select((state) => state.count),
102
+ name: userStore.select((state) => state.name),
103
+ })(MyComponent);
104
+ ```
105
+
106
+ - Selected values are merged into the component's props.
107
+ - Re-renders only when selected values change (shallow equality).
108
+ - Subscriptions are automatically managed (mount/unmount).
109
+ - Multiple stores can be bound to a single component.
110
+
111
+ #### Lifecycle Callbacks
112
+
113
+ The optional second argument adds lifecycle hooks:
114
+
115
+ ```jsx
116
+ const Timer = connect(
117
+ { elapsed: timerStore.select((s) => s.elapsed) },
118
+ {
119
+ onMount: ({ dom, props }) => {
120
+ // Called once after first render. DOM element is available.
121
+ const id = setInterval(() => timerStore.dispatch('tick'), 1000);
122
+ return () => clearInterval(id); // cleanup — called on destroy
123
+ },
124
+ onUpdate: ({ dom, props }) => {
125
+ // Called after every store-driven re-render (not on initial mount).
126
+ console.log('Timer updated:', dom.textContent);
127
+ },
128
+ onDestroy: ({ props }) => {
129
+ // Called when component is removed from the DOM.
130
+ console.log('Timer removed');
131
+ },
132
+ onError: ({ error, props }) => {
133
+ // Called when the component throws during render. Return fallback VNode.
134
+ return h('div', { className: 'error' }, `Error: ${error.message}`);
135
+ },
136
+ }
137
+ )(TimerView);
138
+ ```
139
+
140
+ - **`onMount({ dom, props })`** — fires once after first render. `dom` is the rendered DOM element. Can return a cleanup function that runs on destroy.
141
+ - **`onUpdate({ dom, props })`** — fires after every store-driven re-render (not on initial mount). Useful for DOM measurement, animations, or logging.
142
+ - **`onDestroy({ props })`** — fires when the component is removed, after cleanup.
143
+ - **`onError({ error, props })`** — catches errors thrown during render. Return a fallback VNode (or `null`). The component stays subscribed and recovers on the next successful re-render.
144
+ - Re-renders do **not** re-trigger `onMount`.
145
+ - For components that only need lifecycle (no store bindings), pass empty bindings: `connect({}, { onMount })(Component)`.
146
+
147
+ ### `render(vnode, container)`
148
+
149
+ Mounts a virtual DOM tree into a real DOM container. Subsequent calls to `render` with the same container diff and patch.
150
+
151
+ ```js
152
+ render(<App />, document.getElementById('app'));
153
+ ```
154
+
155
+ ### `h(type, props, ...children)` / `createElement`
156
+
157
+ JSX pragma. You don't call this directly — your JSX compiler transforms `<div>` into `h('div', null)`.
158
+
159
+ ### `Fragment`
160
+
161
+ Groups children without adding a wrapper DOM node.
162
+
163
+ ```jsx
164
+ <>
165
+ <span>a</span>
166
+ <span>b</span>
167
+ </>
168
+ ```
169
+
170
+ ### `createRouter({ routes, initialPath? })`
171
+
172
+ Creates a store-based client-side router.
173
+
174
+ ```jsx
175
+ import { h, createRouter, render } from 'pulse-ui';
176
+
177
+ const router = createRouter({
178
+ routes: [
179
+ { path: '/' },
180
+ { path: '/users/:id' },
181
+ { path: '*' },
182
+ ],
183
+ });
184
+
185
+ const { Route, Link } = router;
186
+
187
+ function App() {
188
+ return (
189
+ <div>
190
+ <nav>
191
+ <Link to="/">Home</Link>
192
+ <Link to="/users/1">User 1</Link>
193
+ </nav>
194
+ <Route path="/" component={Home} />
195
+ <Route path="/users/:id" component={UserProfile} />
196
+ <Route path="*" component={NotFound} />
197
+ </div>
198
+ );
199
+ }
200
+
201
+ render(<App />, document.getElementById('app'));
202
+ ```
203
+
204
+ Returns a `Router` object with:
205
+
206
+ - **`store`** — a Pulse store holding `{ path, params, query, matched }`. Connect any component to route state.
207
+ - **`navigate(path)`** — push a new history entry and update the store.
208
+ - **`redirect(path)`** — replace the current history entry (back button skips it).
209
+ - **`back()` / `forward()`** — browser history navigation.
210
+ - **`Route`** — connected component that renders its `component` prop when the path matches. Passes `params` to the component.
211
+ - **`Link`** — renders an `<a>` with SPA navigation on click. Modifier clicks (Ctrl, Cmd) open in a new tab.
212
+ - **`Redirect`** — performs a redirect when rendered.
213
+ - **`destroy()`** — removes the `popstate` listener (for cleanup in tests).
214
+
215
+ Path patterns support static paths (`/about`), dynamic params (`/users/:id`), wildcard suffixes (`/dashboard/*`), and catch-all (`*`).
216
+
217
+ ### `flushSync()`
218
+
219
+ Synchronously flushes all pending store-triggered re-renders. Primarily useful for testing.
220
+
221
+ ```js
222
+ store.dispatch('increment');
223
+ flushSync();
224
+ // DOM is now updated
225
+ ```
226
+
227
+ ## How It Works
228
+
229
+ 1. **Stores** hold immutable state. Actions produce new state via pure functions.
230
+ 2. **`connect()`** subscribes components to store slices via selectors.
231
+ 3. When a store changes, connected components whose selected values differ are scheduled for re-render.
232
+ 4. The **scheduler** batches multiple store updates in the same tick into a single render pass.
233
+ 5. The **VDOM engine** diffs the old and new virtual trees and patches only the changed DOM nodes.
234
+
235
+ ```
236
+ Store dispatch → Notify subscribers → Schedule re-render → Expand components
237
+ → Diff VDOM → Patch DOM (single paint)
238
+ ```
239
+
240
+ ## Development
241
+
242
+ ```bash
243
+ npm install
244
+ npm test # run tests (vitest)
245
+ npm run build # build dist/ (vite lib mode)
246
+ ```
247
+
248
+ ## License
249
+
250
+ MIT
@@ -0,0 +1,22 @@
1
+ import type { VNode, Bindings, Lifecycle, ComponentFunction } from './vnode';
2
+ export declare const CONNECTED: unique symbol;
3
+ export declare function connect(bindings: Bindings | null | undefined, lifecycle?: Lifecycle): (Component: ComponentFunction) => {
4
+ (props: Record<string, any>): VNode | null;
5
+ displayName: string;
6
+ };
7
+ export declare class ComponentInstance {
8
+ connectedFn: ComponentFunction;
9
+ props: Record<string, any>;
10
+ prevSelected: Record<string, any>;
11
+ unsubscribers: (() => void)[];
12
+ lastVTree: VNode | null;
13
+ parentDom: Node | null;
14
+ _renderCallback: (() => void) | null;
15
+ _mountCleanup: (() => void) | null;
16
+ constructor(connectedFn: ComponentFunction, props: Record<string, any>);
17
+ mount(parentDom: Node, renderCallback: () => void): void;
18
+ _onStoreChange(): void;
19
+ updateSelected(): void;
20
+ unmount(): void;
21
+ }
22
+ export declare function shallowEqual(a: any, b: any): boolean;
@@ -0,0 +1,4 @@
1
+ import { FRAGMENT } from './vnode';
2
+ import type { VNode, VNodeType } from './vnode';
3
+ export declare function h(type: VNodeType, props: Record<string, any> | null, ...rawChildren: any[]): VNode;
4
+ export { FRAGMENT as Fragment };
package/dist/diff.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { VNode } from './vnode';
2
+ export declare const PATCH: {
3
+ readonly CREATE: "CREATE";
4
+ readonly REMOVE: "REMOVE";
5
+ readonly REPLACE: "REPLACE";
6
+ readonly UPDATE: "UPDATE";
7
+ readonly TEXT: "TEXT";
8
+ readonly MOVE: "MOVE";
9
+ };
10
+ export type PatchType = typeof PATCH[keyof typeof PATCH];
11
+ export interface PropPatches {
12
+ set: Record<string, any>;
13
+ remove: string[];
14
+ }
15
+ export type Patch = {
16
+ type: typeof PATCH.CREATE;
17
+ newVNode: VNode;
18
+ anchor?: VNode | null;
19
+ } | {
20
+ type: typeof PATCH.REMOVE;
21
+ target: VNode;
22
+ } | {
23
+ type: typeof PATCH.REPLACE;
24
+ oldVNode: VNode;
25
+ newVNode: VNode;
26
+ } | {
27
+ type: typeof PATCH.UPDATE;
28
+ target: VNode;
29
+ propPatches: PropPatches;
30
+ } | {
31
+ type: typeof PATCH.TEXT;
32
+ oldVNode: VNode;
33
+ newVNode: VNode;
34
+ } | {
35
+ type: typeof PATCH.MOVE;
36
+ vnode: VNode;
37
+ anchor: VNode | null;
38
+ childPatches: Patch[];
39
+ };
40
+ export declare function diff(oldVNode: VNode | null, newVNode: VNode | null): Patch[];
@@ -0,0 +1,9 @@
1
+ export { h, h as createElement, Fragment } from './createElement';
2
+ export { createStore } from './store';
3
+ export { connect } from './connect';
4
+ export { render } from './render';
5
+ export { flushSync } from './scheduler';
6
+ export { createRouter } from './router';
7
+ export type { VNode, ComponentFunction, Bindings, Lifecycle } from './vnode';
8
+ export type { Store, StoreConfig, StoreActions, SelectorBinding } from './store';
9
+ export type { RouteState, RouteConfig, RouterOptions, Router } from './router';
@@ -0,0 +1,5 @@
1
+ import type { VNode } from './vnode';
2
+ import type { Patch } from './diff';
3
+ export declare function createDOMNode(vnode: VNode): Node;
4
+ export declare function applyProps(el: HTMLElement, oldProps: Record<string, any>, newProps: Record<string, any>): void;
5
+ export declare function applyPatches(parentDom: Node, patches: Patch[]): void;
package/dist/pulse.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var et=Object.defineProperty;var nt=(t,e,n)=>e in t?et(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var _=(t,e,n)=>nt(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=Symbol("TEXT_NODE"),$=Symbol("FRAGMENT");function F(t){return{type:j,props:{nodeValue:String(t)},children:[],key:null}}function st(t){return t==null||typeof t=="boolean"?null:typeof t=="string"||typeof t=="number"?F(t):t}function X(t){const e=[];for(const n of t)if(Array.isArray(n))e.push(...X(n));else{const s=st(n);s!==null&&e.push(s)}return e}function P(t,e,...n){e=e||{};const s=e.key??null;e.key!==void 0&&(e={...e},delete e.key);const r=X(n);return{type:t,props:e,children:r,key:s}}function z(t){let e=t.state;const n=t.actions,s=new Set;function r(){return e}function o(u,d){const l=n[u];if(!l)throw new Error(`[pulse] Unknown action: "${u}"`);const m=l(e,d);if(m!==e){e=m;for(const p of s)p(e)}}function c(u){return s.add(u),()=>{s.delete(u)}}function a(u){return{store:i,selector:u}}const i={getState:r,dispatch:o,subscribe:c,select:a};return i}let C=!1;const V=new Set;function ot(t){V.add(t),C||(C=!0,queueMicrotask(rt))}function rt(){const t=[...V];V.clear(),C=!1;for(const e of t)e()}function ct(){const t=[...V];V.clear(),C=!1;for(const e of t)e()}const K=Symbol("PULSE_CONNECTED");function B(t,e){return function(s){const r=t||{};function o(c){const a={};for(const i in r){const{store:u,selector:d}=r[i];a[i]=d(u.getState())}return s({...a,...c})}return o[K]=!0,o._bindings=r,o._innerComponent=s,e&&(o._lifecycle=e),o.displayName=`Connected(${s.displayName||s.name||"Anonymous"})`,o}}class it{constructor(e,n){_(this,"connectedFn");_(this,"props");_(this,"prevSelected");_(this,"unsubscribers");_(this,"lastVTree");_(this,"parentDom");_(this,"_renderCallback");_(this,"_mountCleanup");this.connectedFn=e,this.props=n,this.prevSelected={},this.unsubscribers=[],this.lastVTree=null,this.parentDom=null,this._renderCallback=null,this._mountCleanup=null}mount(e,n){var o;this.parentDom=e,this._renderCallback=n;const s=this.connectedFn._bindings;for(const c in s){const{store:a,selector:i}=s[c];this.prevSelected[c]=i(a.getState())}for(const c in s){const{store:a}=s[c],i=a.subscribe(()=>{this._onStoreChange()});this.unsubscribers.push(i)}const r=this.connectedFn._lifecycle;if(r!=null&&r.onMount){const c=r.onMount({dom:(o=this.lastVTree)==null?void 0:o._dom,props:this.props});typeof c=="function"&&(this._mountCleanup=c)}}_onStoreChange(){const e=this.connectedFn._bindings;let n=!1;for(const s in e){const{store:r,selector:o}=e[s],c=o(r.getState());if(!ut(c,this.prevSelected[s])){n=!0;break}}n&&ot(this._renderCallback)}updateSelected(){const e=this.connectedFn._bindings;for(const n in e){const{store:s,selector:r}=e[n];this.prevSelected[n]=r(s.getState())}}unmount(){this._mountCleanup&&(this._mountCleanup(),this._mountCleanup=null);const e=this.connectedFn._lifecycle;e!=null&&e.onDestroy&&e.onDestroy({props:this.props});for(const n of this.unsubscribers)n();this.unsubscribers=[],this._renderCallback=null}}function ut(t,e){if(Object.is(t,e))return!0;if(typeof t!="object"||typeof e!="object"||t===null||e===null)return!1;const n=Object.keys(t),s=Object.keys(e);if(n.length!==s.length)return!1;for(const r of n)if(!Object.prototype.hasOwnProperty.call(e,r)||!Object.is(t[r],e[r]))return!1;return!0}const f={CREATE:"CREATE",REMOVE:"REMOVE",REPLACE:"REPLACE",UPDATE:"UPDATE",TEXT:"TEXT",MOVE:"MOVE"};function k(t,e){if(e==null&&t==null)return[];if(e==null)return[{type:f.REMOVE,target:t}];if(t==null)return[{type:f.CREATE,newVNode:e}];if(t.type!==e.type)return[{type:f.REPLACE,oldVNode:t,newVNode:e}];if(e._dom=t._dom,t.type===j)return t.props.nodeValue!==e.props.nodeValue?[{type:f.TEXT,oldVNode:t,newVNode:e}]:[];const n=[],s=at(t.props,e.props);s&&n.push({type:f.UPDATE,target:t,propPatches:s});const r=lt(t.children,e.children);return n.push(...r),n}function at(t,e){const n={},s=[];let r=!1;for(const o in e)o!=="children"&&t[o]!==e[o]&&(n[o]=e[o],r=!0);for(const o in t)o!=="children"&&(o in e||(s.push(o),r=!0));return r?{set:n,remove:s}:null}function N(t,e){return t==null||e==null?!1:t.type===e.type&&t.key===e.key}function U(t,e){const n=new Set;let s=0,r=0;for(const o of t)o!=null&&(o.key!=null?(s++,n.has(o.key)&&console.warn(`[pulse] Duplicate key "${String(o.key)}" in ${e} children. Keys must be unique among siblings.`),n.add(o.key)):r++);s>0&&r>0&&console.warn(`[pulse] Mixed keyed and unkeyed children in ${e} list (${s} keyed, ${r} unkeyed). Either all children should have keys or none should.`)}function lt(t,e){var l;process.env.NODE_ENV!=="production"&&(U(t,"old"),U(e,"new"));const n=[];let s=0,r=t.length-1,o=0,c=e.length-1,a=t[s],i=t[r],u=e[o],d=e[c];for(;s<=r&&o<=c;){if(a==null){a=t[++s];continue}if(i==null){i=t[--r];continue}if(N(a,u))n.push(...k(a,u)),a=t[++s],u=e[++o];else if(N(i,d))n.push(...k(i,d)),i=t[--r],d=e[--c];else if(N(a,d))n.push({type:f.MOVE,vnode:a,anchor:t[r+1]||null,childPatches:k(a,d)}),a=t[++s],d=e[--c];else if(N(i,u))n.push({type:f.MOVE,vnode:i,anchor:a,childPatches:k(i,u)}),i=t[--r],u=e[++o];else break}if(s<=r&&o<=c){const m=new Map;for(let p=s;p<=r;p++){const g=(l=t[p])==null?void 0:l.key;g!=null&&m.set(g,p)}for(;o<=c;){u=e[o];const p=u.key!=null?m.get(u.key):void 0;if(p!==void 0){const g=t[p];n.push({type:f.MOVE,vnode:g,anchor:t[s]||null,childPatches:k(g,u)}),t[p]=null,m.delete(u.key)}else n.push({type:f.CREATE,newVNode:u,anchor:t[s]||null});o++}for(let p=s;p<=r;p++)t[p]!=null&&n.push({type:f.REMOVE,target:t[p]})}if(s>r){const m=e[c+1]||null;for(let p=o;p<=c;p++)n.push({type:f.CREATE,newVNode:e[p],anchor:m})}else if(o>c)for(let m=s;m<=r;m++)t[m]!=null&&n.push({type:f.REMOVE,target:t[m]});return n}function O(t){if(t.type===j){const n=document.createTextNode(t.props.nodeValue);return t._dom=n,n}if(t.type===$){const n=document.createDocumentFragment();for(const s of t.children)n.appendChild(O(s));return t._dom=n,n}const e=document.createElement(t.type);ft(e,{},t.props);for(const n of t.children)e.appendChild(O(n));return t._dom=e,e}function ft(t,e,n){for(const s in e)s==="children"||s==="key"||s in n||Q(t,s,e[s]);for(const s in n)s==="children"||s==="key"||e[s]!==n[s]&&G(t,s,n[s],e[s])}function G(t,e,n,s){if(e.startsWith("on")){const r=e.slice(2).toLowerCase();s&&t.removeEventListener(r,s),n&&t.addEventListener(r,n)}else if(e==="className")t.className=n||"";else if(e==="style"&&typeof n=="object"){if(typeof s=="object"&&s)for(const r in s)r in n||(t.style[r]="");Object.assign(t.style,n)}else e==="ref"?typeof n=="function"&&n(t):n===!0?t.setAttribute(e,""):n===!1||n==null?t.removeAttribute(e):t.setAttribute(e,n)}function Q(t,e,n){e.startsWith("on")?t.removeEventListener(e.slice(2).toLowerCase(),n):e==="className"?t.className="":t.removeAttribute(e)}function M(t,e){var n,s,r;for(const o of e)switch(o.type){case f.CREATE:{const c=O(o.newVNode);(n=o.anchor)!=null&&n._dom?t.insertBefore(c,o.anchor._dom):t.appendChild(c);break}case f.REMOVE:{const c=o.target._dom;c!=null&&c.parentNode&&c.parentNode.removeChild(c);break}case f.REPLACE:{const c=O(o.newVNode),a=o.oldVNode._dom;a!=null&&a.parentNode&&a.parentNode.replaceChild(c,a);break}case f.UPDATE:{const c=o.target._dom,{set:a,remove:i}=o.propPatches;for(const u of i)Q(c,u,o.target.props[u]);for(const u in a)G(c,u,a[u],o.target.props[u]);break}case f.TEXT:{const c=o.oldVNode._dom;c&&(c.nodeValue=o.newVNode.props.nodeValue);break}case f.MOVE:{const c=o.vnode._dom;c&&((s=o.anchor)!=null&&s._dom?t.insertBefore(c,o.anchor._dom):t.appendChild(c)),(r=o.childPatches)!=null&&r.length&&c&&M(c,o.childPatches);break}}}const L=new WeakMap;function pt(t,e){const n=L.get(e);if(n){const s=S(t,e),r=[];A(n.vTree,r);const o=k(n.vTree,s);M(e,o);const c=[];s&&A(s,c);const a=new Set(c);for(const u of r)a.has(u)||u.unmount();const i=new Set(r);for(const u of c)i.has(u)||u.mount(e,()=>D(u,e));L.set(e,{vTree:s})}else{const s=S(t,e);if(!s)return;const r=O(s);e.appendChild(r);const o=[];A(s,o);for(const c of o)c.mount(e,()=>D(c,e));L.set(e,{vTree:s})}}function S(t,e){var n;if(t==null)return null;if(typeof t.type=="function"){if(t.type[K]){const r=t.type._lifecycle;try{const o=new it(t.type,t.props),c=t.type(t.props),i=S(c,e)??F("");return i._instance=o,o.lastVTree=i,i}catch(o){if(r!=null&&r.onError){const c=r.onError({error:o,props:t.props});return S(c,e)}throw o}}const s=t.type({...t.props,children:t.children});return S(s,e)}return(n=t.children)!=null&&n.length&&(t.children=t.children.map(s=>S(s,e)).filter(s=>s!=null)),t}function D(t,e){var r,o;const n=t.connectedFn,s=n._lifecycle;try{const c=n(t.props),i=S(c,e)??F("");if(t.lastVTree){const u=k(t.lastVTree,i),d=((r=t.lastVTree._dom)==null?void 0:r.parentNode)||e;M(d,u);for(const l of u)l.type===f.REMOVE?R(l.target,t):l.type===f.REPLACE&&R(l.oldVNode,t);i._dom||(i._dom=t.lastVTree._dom)}i._instance=t,t.lastVTree=i,s!=null&&s.onUpdate&&s.onUpdate({dom:i==null?void 0:i._dom,props:t.props}),t.updateSelected()}catch(c){if(s!=null&&s.onError){const a=s.onError({error:c,props:t.props}),i=S(a,e);if(t.lastVTree&&i){const u=k(t.lastVTree,i),d=((o=t.lastVTree._dom)==null?void 0:o.parentNode)||e;M(d,u);for(const l of u)l.type===f.REMOVE?R(l.target,t):l.type===f.REPLACE&&R(l.oldVNode,t);i._dom||(i._dom=t.lastVTree._dom)}t.lastVTree=i,t.updateSelected()}else throw c}}function R(t,e){if(t&&(t._instance&&t._instance!==e&&t._instance.unmount(),t.children))for(const n of t.children)R(n,e)}function A(t,e){if(t&&(t._instance&&e.push(t._instance),t.children))for(const n of t.children)A(n,e)}function x(t){return t.length>1&&t.endsWith("/")?t.slice(0,-1):t||"/"}function W(t){const e={};if(!t)return e;const n=t.startsWith("?")?t.slice(1):t;return n&&new URLSearchParams(n).forEach((r,o)=>{e[o]=r}),e}function H(t,e){const n=x(t),s=x(e);if(s==="*")return{params:{"*":n}};const r=n==="/"?[""]:n.split("/").slice(1),o=s==="/"?[""]:s.split("/").slice(1);if(o.length>0&&o[o.length-1]==="*"){const i=o.slice(0,-1);if(r.length<i.length)return null;const u={};for(let l=0;l<i.length;l++){const m=i[l];if(m.startsWith(":"))u[m.slice(1)]=r[l];else if(m!==r[l])return null}const d=r.slice(i.length).join("/");return u["*"]=d,{params:u}}if(r.length!==o.length)return null;const a={};for(let i=0;i<o.length;i++){const u=o[i];if(u.startsWith(":"))a[u.slice(1)]=r[i];else if(u!==r[i])return null}return{params:a}}function q(t,e){for(const n of e){const s=H(t,n.path);if(s)return{pattern:n.path,params:s.params}}return null}function ht(t){const{routes:e,initialPath:n}=t,s=n??window.location.pathname,r=n?"":window.location.search,o=x(s),c=W(r),a=q(o,e),i=z({state:{path:o,params:(a==null?void 0:a.params)??{},query:c,matched:(a==null?void 0:a.pattern)??null},actions:{_sync:(h,y)=>y}});function u(h){const y=h.indexOf("?"),T=x(y>=0?h.slice(0,y):h),w=y>=0?h.slice(y+1):"",E=W(w),b=q(T,e);return{path:T,params:(b==null?void 0:b.params)??{},query:E,matched:(b==null?void 0:b.pattern)??null}}function d(h){const y=u(h);window.history.pushState(null,"",h),i.dispatch("_sync",y)}function l(h){const y=u(h);window.history.replaceState(null,"",h),i.dispatch("_sync",y)}function m(){window.history.back()}function p(){window.history.forward()}function g(){const h=u(window.location.pathname+window.location.search);i.dispatch("_sync",h)}window.addEventListener("popstate",g);function J(){window.removeEventListener("popstate",g)}const Y=B({_path:i.select(h=>h.path)})(function(y){const{_path:T,path:w,component:E,children:b,...tt}=y,I=H(T,w);return I?E?P(E,{...tt,params:I.params}):(b==null?void 0:b[0])??null:null});function Z(h){const{to:y,children:T,...w}=h;return P("a",{...w,href:y,onClick:E=>{E.metaKey||E.ctrlKey||E.shiftKey||E.button!==0||(E.preventDefault(),d(y))}},...T||[])}function v(h){return l(h.to),null}return{store:i,navigate:d,redirect:l,back:m,forward:p,destroy:J,Route:Y,Link:Z,Redirect:v}}exports.Fragment=$;exports.connect=B;exports.createElement=P;exports.createRouter=ht;exports.createStore=z;exports.flushSync=ct;exports.h=P;exports.render=pt;
2
+ //# sourceMappingURL=pulse.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pulse.cjs","sources":["../src/vnode.ts","../src/createElement.ts","../src/store.ts","../src/scheduler.ts","../src/connect.ts","../src/diff.ts","../src/patch.ts","../src/render.ts","../src/router.ts"],"sourcesContent":["import type { ComponentInstance } from './connect';\nimport type { SelectorBinding } from './store';\n\nexport const TEXT_NODE: unique symbol = Symbol('TEXT_NODE');\nexport const FRAGMENT: unique symbol = Symbol('FRAGMENT');\n\nexport type VNodeType = string | typeof TEXT_NODE | typeof FRAGMENT | ComponentFunction;\n\nexport interface VNode {\n type: VNodeType;\n props: Record<string, any>;\n children: VNode[];\n key: string | number | null;\n _dom?: Node | null;\n _instance?: ComponentInstance | null;\n}\n\nexport type ComponentFunction = (props: Record<string, any>) => VNode | null;\n\nexport interface Bindings {\n [propName: string]: SelectorBinding<any, any>;\n}\n\nexport interface Lifecycle {\n onMount?: (ctx: { dom: Node | null | undefined; props: Record<string, any> }) => void | (() => void);\n onUpdate?: (ctx: { dom: Node | null | undefined; props: Record<string, any> }) => void;\n onError?: (ctx: { error: unknown; props: Record<string, any> }) => VNode | null;\n onDestroy?: (ctx: { props: Record<string, any> }) => void;\n}\n\nexport function createTextVNode(text: string | number): VNode {\n return {\n type: TEXT_NODE,\n props: { nodeValue: String(text) },\n children: [],\n key: null,\n };\n}\n\nexport function normalizeChild(child: any): VNode | null {\n if (child == null || typeof child === 'boolean') return null;\n if (typeof child === 'string' || typeof child === 'number') {\n return createTextVNode(child);\n }\n return child as VNode;\n}\n\nexport function flattenChildren(rawChildren: any[]): VNode[] {\n const result: VNode[] = [];\n for (const child of rawChildren) {\n if (Array.isArray(child)) {\n result.push(...flattenChildren(child));\n } else {\n const normalized = normalizeChild(child);\n if (normalized !== null) result.push(normalized);\n }\n }\n return result;\n}\n","import { FRAGMENT, flattenChildren } from './vnode';\nimport type { VNode, VNodeType } from './vnode';\n\nexport function h(type: VNodeType, props: Record<string, any> | null, ...rawChildren: any[]): VNode {\n props = props || {};\n const key = props.key ?? null;\n\n if (props.key !== undefined) {\n props = { ...props };\n delete props.key;\n }\n\n const children = flattenChildren(rawChildren);\n\n return { type, props, children, key };\n}\n\nexport { FRAGMENT as Fragment };\n","export interface StoreActions<S> {\n [actionName: string]: (state: S, payload?: any) => S;\n}\n\nexport interface StoreConfig<S> {\n state: S;\n actions: StoreActions<S>;\n}\n\nexport interface SelectorBinding<S, R> {\n store: Store<S>;\n selector: (state: S) => R;\n}\n\nexport interface Store<S> {\n getState(): S;\n dispatch(actionName: string, payload?: any): void;\n subscribe(listener: (state: S) => void): () => void;\n select<R>(selectorFn: (state: S) => R): SelectorBinding<S, R>;\n}\n\nexport function createStore<S>(config: StoreConfig<S>): Store<S> {\n let state: S = config.state;\n const actions = config.actions;\n const listeners = new Set<(state: S) => void>();\n\n function getState(): S {\n return state;\n }\n\n function dispatch(actionName: string, payload?: any): void {\n const action = actions[actionName];\n if (!action) {\n throw new Error(`[pulse] Unknown action: \"${actionName}\"`);\n }\n const nextState = action(state, payload);\n if (nextState === state) return;\n state = nextState;\n for (const listener of listeners) {\n listener(state);\n }\n }\n\n function subscribe(listener: (state: S) => void): () => void {\n listeners.add(listener);\n return () => { listeners.delete(listener); };\n }\n\n function select<R>(selectorFn: (state: S) => R): SelectorBinding<S, R> {\n return { store: storeObj, selector: selectorFn };\n }\n\n const storeObj: Store<S> = { getState, dispatch, subscribe, select };\n return storeObj;\n}\n","let pending = false;\nconst queue = new Set<() => void>();\n\nexport function scheduleUpdate(callback: () => void): void {\n queue.add(callback);\n if (!pending) {\n pending = true;\n queueMicrotask(flush);\n }\n}\n\nfunction flush(): void {\n const batch = [...queue];\n queue.clear();\n pending = false;\n for (const callback of batch) {\n callback();\n }\n}\n\nexport function flushSync(): void {\n const batch = [...queue];\n queue.clear();\n pending = false;\n for (const callback of batch) {\n callback();\n }\n}\n","import { scheduleUpdate } from './scheduler';\nimport type { VNode, Bindings, Lifecycle, ComponentFunction } from './vnode';\n\nexport const CONNECTED: unique symbol = Symbol('PULSE_CONNECTED');\n\nexport function connect(\n bindings: Bindings | null | undefined,\n lifecycle?: Lifecycle,\n) {\n return function wrapComponent(Component: ComponentFunction) {\n const b = bindings || {};\n\n function ConnectedComponent(props: Record<string, any>): VNode | null {\n const selectedProps: Record<string, any> = {};\n for (const propName in b) {\n const { store, selector } = b[propName];\n selectedProps[propName] = selector(store.getState());\n }\n return Component({ ...selectedProps, ...props });\n }\n\n (ConnectedComponent as any)[CONNECTED] = true;\n (ConnectedComponent as any)._bindings = b;\n (ConnectedComponent as any)._innerComponent = Component;\n if (lifecycle) (ConnectedComponent as any)._lifecycle = lifecycle;\n ConnectedComponent.displayName =\n `Connected(${(Component as any).displayName || Component.name || 'Anonymous'})`;\n\n return ConnectedComponent;\n };\n}\n\nexport class ComponentInstance {\n connectedFn: ComponentFunction;\n props: Record<string, any>;\n prevSelected: Record<string, any>;\n unsubscribers: (() => void)[];\n lastVTree: VNode | null;\n parentDom: Node | null;\n _renderCallback: (() => void) | null;\n _mountCleanup: (() => void) | null;\n\n constructor(connectedFn: ComponentFunction, props: Record<string, any>) {\n this.connectedFn = connectedFn;\n this.props = props;\n this.prevSelected = {};\n this.unsubscribers = [];\n this.lastVTree = null;\n this.parentDom = null;\n this._renderCallback = null;\n this._mountCleanup = null;\n }\n\n mount(parentDom: Node, renderCallback: () => void): void {\n this.parentDom = parentDom;\n this._renderCallback = renderCallback;\n\n const bindings: Bindings = (this.connectedFn as any)._bindings;\n\n for (const propName in bindings) {\n const { store, selector } = bindings[propName];\n this.prevSelected[propName] = selector(store.getState());\n }\n\n for (const propName in bindings) {\n const { store } = bindings[propName];\n const unsub = store.subscribe(() => {\n this._onStoreChange();\n });\n this.unsubscribers.push(unsub);\n }\n\n // Lifecycle: call onMount after subscriptions are live\n const lifecycle: Lifecycle | undefined = (this.connectedFn as any)._lifecycle;\n if (lifecycle?.onMount) {\n const cleanup = lifecycle.onMount({\n dom: this.lastVTree?._dom,\n props: this.props,\n });\n if (typeof cleanup === 'function') {\n this._mountCleanup = cleanup;\n }\n }\n }\n\n _onStoreChange(): void {\n const bindings: Bindings = (this.connectedFn as any)._bindings;\n let changed = false;\n\n for (const propName in bindings) {\n const { store, selector } = bindings[propName];\n const newValue = selector(store.getState());\n if (!shallowEqual(newValue, this.prevSelected[propName])) {\n changed = true;\n break;\n }\n }\n\n if (changed) {\n scheduleUpdate(this._renderCallback!);\n }\n }\n\n updateSelected(): void {\n const bindings: Bindings = (this.connectedFn as any)._bindings;\n for (const propName in bindings) {\n const { store, selector } = bindings[propName];\n this.prevSelected[propName] = selector(store.getState());\n }\n }\n\n unmount(): void {\n // Lifecycle: cleanup from onMount, then onDestroy\n if (this._mountCleanup) {\n this._mountCleanup();\n this._mountCleanup = null;\n }\n const lifecycle: Lifecycle | undefined = (this.connectedFn as any)._lifecycle;\n if (lifecycle?.onDestroy) {\n lifecycle.onDestroy({ props: this.props });\n }\n\n for (const unsub of this.unsubscribers) {\n unsub();\n }\n this.unsubscribers = [];\n this._renderCallback = null;\n }\n}\n\nexport function shallowEqual(a: any, b: any): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n if (a === null || b === null) return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key) || !Object.is(a[key], b[key])) {\n return false;\n }\n }\n return true;\n}\n","import { TEXT_NODE } from './vnode';\nimport type { VNode } from './vnode';\n\nexport const PATCH = {\n CREATE: 'CREATE',\n REMOVE: 'REMOVE',\n REPLACE: 'REPLACE',\n UPDATE: 'UPDATE',\n TEXT: 'TEXT',\n MOVE: 'MOVE',\n} as const;\n\nexport type PatchType = typeof PATCH[keyof typeof PATCH];\n\nexport interface PropPatches {\n set: Record<string, any>;\n remove: string[];\n}\n\nexport type Patch =\n | { type: typeof PATCH.CREATE; newVNode: VNode; anchor?: VNode | null }\n | { type: typeof PATCH.REMOVE; target: VNode }\n | { type: typeof PATCH.REPLACE; oldVNode: VNode; newVNode: VNode }\n | { type: typeof PATCH.UPDATE; target: VNode; propPatches: PropPatches }\n | { type: typeof PATCH.TEXT; oldVNode: VNode; newVNode: VNode }\n | { type: typeof PATCH.MOVE; vnode: VNode; anchor: VNode | null; childPatches: Patch[] };\n\nexport function diff(oldVNode: VNode | null, newVNode: VNode | null): Patch[] {\n if (newVNode == null && oldVNode == null) return [];\n if (newVNode == null) return [{ type: PATCH.REMOVE, target: oldVNode! }];\n if (oldVNode == null) return [{ type: PATCH.CREATE, newVNode }];\n\n if (oldVNode.type !== newVNode.type) {\n return [{ type: PATCH.REPLACE, oldVNode, newVNode }];\n }\n\n // Transfer _dom reference: the new vnode represents the same DOM node\n newVNode._dom = oldVNode._dom;\n\n if (oldVNode.type === TEXT_NODE) {\n if (oldVNode.props.nodeValue !== newVNode.props.nodeValue) {\n return [{ type: PATCH.TEXT, oldVNode, newVNode }];\n }\n return [];\n }\n\n const patches: Patch[] = [];\n\n const propPatches = diffProps(oldVNode.props, newVNode.props);\n if (propPatches) {\n patches.push({ type: PATCH.UPDATE, target: oldVNode, propPatches });\n }\n\n const childPatches = diffChildren(oldVNode.children, newVNode.children);\n patches.push(...childPatches);\n\n return patches;\n}\n\nfunction diffProps(\n oldProps: Record<string, any>,\n newProps: Record<string, any>,\n): PropPatches | null {\n const set: Record<string, any> = {};\n const remove: string[] = [];\n let hasChanges = false;\n\n for (const key in newProps) {\n if (key === 'children') continue;\n if (oldProps[key] !== newProps[key]) {\n set[key] = newProps[key];\n hasChanges = true;\n }\n }\n\n for (const key in oldProps) {\n if (key === 'children') continue;\n if (!(key in newProps)) {\n remove.push(key);\n hasChanges = true;\n }\n }\n\n return hasChanges ? { set, remove } : null;\n}\n\nfunction sameVNode(a: VNode | null, b: VNode | null): boolean {\n if (a == null || b == null) return false;\n return a.type === b.type && a.key === b.key;\n}\n\nfunction warnChildKeys(children: (VNode | null)[], label: string): void {\n const seen = new Set<string | number>();\n let keyedCount = 0;\n let unkeyedCount = 0;\n\n for (const child of children) {\n if (child == null) continue;\n if (child.key != null) {\n keyedCount++;\n if (seen.has(child.key)) {\n console.warn(\n `[pulse] Duplicate key \"${String(child.key)}\" in ${label} children. ` +\n `Keys must be unique among siblings.`,\n );\n }\n seen.add(child.key);\n } else {\n unkeyedCount++;\n }\n }\n\n if (keyedCount > 0 && unkeyedCount > 0) {\n console.warn(\n `[pulse] Mixed keyed and unkeyed children in ${label} list ` +\n `(${keyedCount} keyed, ${unkeyedCount} unkeyed). ` +\n `Either all children should have keys or none should.`,\n );\n }\n}\n\nfunction diffChildren(oldChildren: (VNode | null)[], newChildren: VNode[]): Patch[] {\n if (process.env.NODE_ENV !== 'production') {\n warnChildKeys(oldChildren, 'old');\n warnChildKeys(newChildren, 'new');\n }\n\n const patches: Patch[] = [];\n\n let oldStartIdx = 0;\n let oldEndIdx = oldChildren.length - 1;\n let newStartIdx = 0;\n let newEndIdx = newChildren.length - 1;\n\n let oldStartVNode = oldChildren[oldStartIdx];\n let oldEndVNode = oldChildren[oldEndIdx];\n let newStartVNode = newChildren[newStartIdx];\n let newEndVNode = newChildren[newEndIdx];\n\n // Phase 1: two-pointer scan\n while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {\n if (oldStartVNode == null) {\n oldStartVNode = oldChildren[++oldStartIdx];\n continue;\n }\n if (oldEndVNode == null) {\n oldEndVNode = oldChildren[--oldEndIdx];\n continue;\n }\n\n if (sameVNode(oldStartVNode, newStartVNode)) {\n patches.push(...diff(oldStartVNode, newStartVNode));\n oldStartVNode = oldChildren[++oldStartIdx];\n newStartVNode = newChildren[++newStartIdx];\n } else if (sameVNode(oldEndVNode, newEndVNode)) {\n patches.push(...diff(oldEndVNode, newEndVNode));\n oldEndVNode = oldChildren[--oldEndIdx];\n newEndVNode = newChildren[--newEndIdx];\n } else if (sameVNode(oldStartVNode, newEndVNode)) {\n patches.push({\n type: PATCH.MOVE,\n vnode: oldStartVNode!,\n anchor: oldChildren[oldEndIdx + 1] || null,\n childPatches: diff(oldStartVNode, newEndVNode),\n });\n oldStartVNode = oldChildren[++oldStartIdx];\n newEndVNode = newChildren[--newEndIdx];\n } else if (sameVNode(oldEndVNode, newStartVNode)) {\n patches.push({\n type: PATCH.MOVE,\n vnode: oldEndVNode!,\n anchor: oldStartVNode,\n childPatches: diff(oldEndVNode, newStartVNode),\n });\n oldEndVNode = oldChildren[--oldEndIdx];\n newStartVNode = newChildren[++newStartIdx];\n } else {\n // Fall through to key-map phase\n break;\n }\n }\n\n // Phase 2: key-map fallback for remaining nodes\n if (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {\n const keyMap = new Map<string | number, number>();\n for (let i = oldStartIdx; i <= oldEndIdx; i++) {\n const key = oldChildren[i]?.key;\n if (key != null) keyMap.set(key, i);\n }\n\n while (newStartIdx <= newEndIdx) {\n newStartVNode = newChildren[newStartIdx];\n const oldIdx = newStartVNode.key != null\n ? keyMap.get(newStartVNode.key)\n : undefined;\n\n if (oldIdx !== undefined) {\n const matchedOld = oldChildren[oldIdx]!;\n patches.push({\n type: PATCH.MOVE,\n vnode: matchedOld,\n anchor: oldChildren[oldStartIdx] || null,\n childPatches: diff(matchedOld, newStartVNode),\n });\n oldChildren[oldIdx] = null;\n keyMap.delete(newStartVNode.key!);\n } else {\n patches.push({\n type: PATCH.CREATE,\n newVNode: newStartVNode,\n anchor: oldChildren[oldStartIdx] || null,\n });\n }\n newStartIdx++;\n }\n\n // Remove unconsumed old children\n for (let i = oldStartIdx; i <= oldEndIdx; i++) {\n if (oldChildren[i] != null) {\n patches.push({ type: PATCH.REMOVE, target: oldChildren[i]! });\n }\n }\n }\n\n // Phase 3: remaining creates or removes\n if (oldStartIdx > oldEndIdx) {\n const anchor = newChildren[newEndIdx + 1] || null;\n for (let i = newStartIdx; i <= newEndIdx; i++) {\n patches.push({ type: PATCH.CREATE, newVNode: newChildren[i], anchor });\n }\n } else if (newStartIdx > newEndIdx) {\n for (let i = oldStartIdx; i <= oldEndIdx; i++) {\n if (oldChildren[i] != null) {\n patches.push({ type: PATCH.REMOVE, target: oldChildren[i]! });\n }\n }\n }\n\n return patches;\n}\n","import { TEXT_NODE, FRAGMENT } from './vnode';\nimport { PATCH } from './diff';\nimport type { VNode } from './vnode';\nimport type { Patch } from './diff';\n\nexport function createDOMNode(vnode: VNode): Node {\n if (vnode.type === TEXT_NODE) {\n const textNode = document.createTextNode(vnode.props.nodeValue);\n vnode._dom = textNode;\n return textNode;\n }\n\n if (vnode.type === FRAGMENT) {\n const frag = document.createDocumentFragment();\n for (const child of vnode.children) {\n frag.appendChild(createDOMNode(child));\n }\n // For fragments, store ref to first child for positioning\n vnode._dom = frag;\n return frag;\n }\n\n const el = document.createElement(vnode.type as string);\n applyProps(el, {}, vnode.props);\n\n for (const child of vnode.children) {\n el.appendChild(createDOMNode(child));\n }\n\n vnode._dom = el;\n return el;\n}\n\nexport function applyProps(\n el: HTMLElement,\n oldProps: Record<string, any>,\n newProps: Record<string, any>,\n): void {\n for (const key in oldProps) {\n if (key === 'children' || key === 'key') continue;\n if (!(key in newProps)) {\n removeProp(el, key, oldProps[key]);\n }\n }\n for (const key in newProps) {\n if (key === 'children' || key === 'key') continue;\n if (oldProps[key] !== newProps[key]) {\n setProp(el, key, newProps[key], oldProps[key]);\n }\n }\n}\n\nfunction setProp(el: HTMLElement, key: string, value: any, oldValue: any): void {\n if (key.startsWith('on')) {\n const eventName = key.slice(2).toLowerCase();\n if (oldValue) el.removeEventListener(eventName, oldValue);\n if (value) el.addEventListener(eventName, value);\n } else if (key === 'className') {\n el.className = value || '';\n } else if (key === 'style' && typeof value === 'object') {\n if (typeof oldValue === 'object' && oldValue) {\n for (const prop in oldValue) {\n if (!(prop in value)) (el.style as any)[prop] = '';\n }\n }\n Object.assign(el.style, value);\n } else if (key === 'ref') {\n if (typeof value === 'function') value(el);\n } else if (value === true) {\n el.setAttribute(key, '');\n } else if (value === false || value == null) {\n el.removeAttribute(key);\n } else {\n el.setAttribute(key, value);\n }\n}\n\nfunction removeProp(el: HTMLElement, key: string, oldValue: any): void {\n if (key.startsWith('on')) {\n el.removeEventListener(key.slice(2).toLowerCase(), oldValue);\n } else if (key === 'className') {\n el.className = '';\n } else {\n el.removeAttribute(key);\n }\n}\n\nexport function applyPatches(parentDom: Node, patches: Patch[]): void {\n for (const patch of patches) {\n switch (patch.type) {\n case PATCH.CREATE: {\n const dom = createDOMNode(patch.newVNode);\n if (patch.anchor?._dom) {\n parentDom.insertBefore(dom, patch.anchor._dom);\n } else {\n parentDom.appendChild(dom);\n }\n break;\n }\n\n case PATCH.REMOVE: {\n const dom = patch.target._dom;\n if (dom?.parentNode) {\n dom.parentNode.removeChild(dom);\n }\n break;\n }\n\n case PATCH.REPLACE: {\n const newDom = createDOMNode(patch.newVNode);\n const oldDom = patch.oldVNode._dom;\n if (oldDom?.parentNode) {\n oldDom.parentNode.replaceChild(newDom, oldDom);\n }\n break;\n }\n\n case PATCH.UPDATE: {\n const dom = patch.target._dom as HTMLElement;\n const { set, remove } = patch.propPatches;\n for (const key of remove) {\n removeProp(dom, key, patch.target.props[key]);\n }\n for (const key in set) {\n setProp(dom, key, set[key], patch.target.props[key]);\n }\n break;\n }\n\n case PATCH.TEXT: {\n const dom = patch.oldVNode._dom;\n if (dom) dom.nodeValue = patch.newVNode.props.nodeValue;\n break;\n }\n\n case PATCH.MOVE: {\n const dom = patch.vnode._dom;\n if (dom) {\n if (patch.anchor?._dom) {\n parentDom.insertBefore(dom, patch.anchor._dom);\n } else {\n parentDom.appendChild(dom);\n }\n }\n if (patch.childPatches?.length && dom) {\n applyPatches(dom, patch.childPatches);\n }\n break;\n }\n }\n }\n}\n","import { diff, PATCH } from './diff';\nimport { createDOMNode, applyPatches } from './patch';\nimport { CONNECTED, ComponentInstance } from './connect';\nimport { TEXT_NODE, FRAGMENT, createTextVNode } from './vnode';\nimport type { VNode, Lifecycle } from './vnode';\nimport type { Patch } from './diff';\n\ninterface RootEntry {\n vTree: VNode;\n}\n\nconst roots = new WeakMap<Node, RootEntry>();\n\nexport function render(vnode: VNode, container: Node): void {\n const prev = roots.get(container);\n\n if (!prev) {\n // First mount\n const expanded = expand(vnode, container);\n if (!expanded) return;\n\n const dom = createDOMNode(expanded);\n container.appendChild(dom);\n\n const instances: ComponentInstance[] = [];\n collectInstances(expanded, instances);\n for (const inst of instances) {\n inst.mount(container, () => reRenderInstance(inst, container));\n }\n\n roots.set(container, { vTree: expanded });\n } else {\n // Update\n const expanded = expand(vnode, container);\n\n const oldInstances: ComponentInstance[] = [];\n collectInstances(prev.vTree, oldInstances);\n\n const patches = diff(prev.vTree, expanded);\n applyPatches(container, patches);\n\n const newInstances: ComponentInstance[] = [];\n if (expanded) collectInstances(expanded, newInstances);\n\n // Unmount removed instances\n const newSet = new Set(newInstances);\n for (const inst of oldInstances) {\n if (!newSet.has(inst)) {\n inst.unmount();\n }\n }\n\n // Mount new instances\n const oldSet = new Set(oldInstances);\n for (const inst of newInstances) {\n if (!oldSet.has(inst)) {\n inst.mount(container, () => reRenderInstance(inst, container));\n }\n }\n\n roots.set(container, { vTree: expanded! });\n }\n}\n\nfunction expand(vnode: VNode | null, parentDom: Node): VNode | null {\n if (vnode == null) return null;\n\n if (typeof vnode.type === 'function') {\n if ((vnode.type as any)[CONNECTED]) {\n // Connected component — with error boundary support\n const lifecycle: Lifecycle | undefined = (vnode.type as any)._lifecycle;\n\n try {\n const instance = new ComponentInstance(vnode.type, vnode.props);\n const childVNode = vnode.type(vnode.props);\n const expanded = expand(childVNode, parentDom);\n\n // Use placeholder for null returns so instance stays in tree (subscribes)\n const result = expanded ?? createTextVNode('');\n result._instance = instance;\n instance.lastVTree = result;\n\n return result;\n } catch (error) {\n if (lifecycle?.onError) {\n const fallbackVNode = lifecycle.onError({ error, props: vnode.props });\n return expand(fallbackVNode, parentDom);\n }\n throw error;\n }\n }\n\n // Plain function component\n const childVNode = vnode.type({ ...vnode.props, children: vnode.children });\n return expand(childVNode, parentDom);\n }\n\n // Element, text, or fragment: recursively expand children\n if (vnode.children?.length) {\n vnode.children = vnode.children\n .map(child => expand(child, parentDom))\n .filter((c): c is VNode => c != null);\n }\n\n return vnode;\n}\n\nfunction reRenderInstance(instance: ComponentInstance, parentDom: Node): void {\n const connectedFn = instance.connectedFn;\n const lifecycle: Lifecycle | undefined = (connectedFn as any)._lifecycle;\n\n try {\n const newVNode = connectedFn(instance.props);\n const rawExpanded = expand(newVNode, parentDom);\n\n // Use placeholder for null returns so instance stays in tree\n const newExpanded = rawExpanded ?? createTextVNode('');\n\n if (instance.lastVTree) {\n const patches = diff(instance.lastVTree, newExpanded);\n\n // Find the actual parent DOM node to patch against\n const domParent = instance.lastVTree._dom?.parentNode || parentDom;\n applyPatches(domParent, patches);\n\n // Unmount child instances in removed/replaced subtrees\n // (skip our own instance — it drives this re-render and must stay alive)\n for (const patch of patches) {\n if (patch.type === PATCH.REMOVE) {\n unmountSubtree(patch.target, instance);\n } else if (patch.type === PATCH.REPLACE) {\n unmountSubtree(patch.oldVNode, instance);\n }\n }\n\n // Transfer the _dom reference from old to new\n if (!newExpanded._dom) {\n newExpanded._dom = instance.lastVTree._dom;\n }\n }\n\n newExpanded._instance = instance;\n instance.lastVTree = newExpanded;\n\n // Lifecycle: onUpdate fires after every re-render (not on initial mount)\n if (lifecycle?.onUpdate) {\n lifecycle.onUpdate({\n dom: newExpanded?._dom,\n props: instance.props,\n });\n }\n\n instance.updateSelected();\n } catch (error) {\n if (lifecycle?.onError) {\n const fallbackVNode = lifecycle.onError({ error, props: instance.props });\n const fallbackExpanded = expand(fallbackVNode, parentDom);\n\n // Replace current DOM with fallback\n if (instance.lastVTree && fallbackExpanded) {\n const patches = diff(instance.lastVTree, fallbackExpanded);\n const domParent = instance.lastVTree._dom?.parentNode || parentDom;\n applyPatches(domParent, patches);\n\n // Unmount child instances but skip our own — it stays subscribed for recovery\n for (const patch of patches) {\n if (patch.type === PATCH.REMOVE) {\n unmountSubtree(patch.target, instance);\n } else if (patch.type === PATCH.REPLACE) {\n unmountSubtree(patch.oldVNode, instance);\n }\n }\n\n if (!fallbackExpanded._dom) {\n fallbackExpanded._dom = instance.lastVTree._dom;\n }\n }\n\n instance.lastVTree = fallbackExpanded;\n instance.updateSelected();\n } else {\n throw error;\n }\n }\n}\n\nfunction unmountSubtree(vnode: VNode | null, skip?: ComponentInstance): void {\n if (!vnode) return;\n if (vnode._instance && vnode._instance !== skip) vnode._instance.unmount();\n if (vnode.children) {\n for (const child of vnode.children) {\n unmountSubtree(child, skip);\n }\n }\n}\n\nfunction collectInstances(vnode: VNode | null, result: ComponentInstance[]): void {\n if (!vnode) return;\n if (vnode._instance) result.push(vnode._instance);\n if (vnode.children) {\n for (const child of vnode.children) {\n collectInstances(child, result);\n }\n }\n}\n","import { createStore } from './store';\nimport { connect } from './connect';\nimport { h } from './createElement';\nimport type { Store } from './store';\nimport type { VNode, ComponentFunction } from './vnode';\n\n// ── Types ──────────────────────────────────────────────────\n\nexport interface RouteState {\n path: string;\n params: Record<string, string>;\n query: Record<string, string>;\n matched: string | null;\n}\n\nexport interface RouteConfig {\n path: string;\n}\n\nexport interface RouterOptions {\n routes: RouteConfig[];\n initialPath?: string;\n}\n\nexport interface Router {\n store: Store<RouteState>;\n navigate: (path: string) => void;\n redirect: (path: string) => void;\n back: () => void;\n forward: () => void;\n destroy: () => void;\n Route: ComponentFunction;\n Link: ComponentFunction;\n Redirect: ComponentFunction;\n}\n\n// ── Path Utilities ─────────────────────────────────────────\n\nfunction normalizePath(path: string): string {\n // Strip trailing slash (but keep root \"/\")\n if (path.length > 1 && path.endsWith('/')) {\n return path.slice(0, -1);\n }\n return path || '/';\n}\n\nfunction parseQuery(search: string): Record<string, string> {\n const result: Record<string, string> = {};\n if (!search) return result;\n const cleaned = search.startsWith('?') ? search.slice(1) : search;\n if (!cleaned) return result;\n const params = new URLSearchParams(cleaned);\n params.forEach((value, key) => {\n result[key] = value;\n });\n return result;\n}\n\n// ── Route Matching ─────────────────────────────────────────\n\ninterface MatchResult {\n pattern: string;\n params: Record<string, string>;\n}\n\nfunction matchSingle(\n path: string,\n pattern: string,\n): { params: Record<string, string> } | null {\n const normalizedPath = normalizePath(path);\n const normalizedPattern = normalizePath(pattern);\n\n // Catch-all wildcard\n if (normalizedPattern === '*') {\n return { params: { '*': normalizedPath } };\n }\n\n const pathSegments = normalizedPath === '/'\n ? ['']\n : normalizedPath.split('/').slice(1);\n const patternSegments = normalizedPattern === '/'\n ? ['']\n : normalizedPattern.split('/').slice(1);\n\n // Check for trailing wildcard (prefix matching)\n const hasTrailingWildcard =\n patternSegments.length > 0 &&\n patternSegments[patternSegments.length - 1] === '*';\n\n if (hasTrailingWildcard) {\n const prefixSegments = patternSegments.slice(0, -1);\n\n // Path must have at least as many segments as the prefix\n if (pathSegments.length < prefixSegments.length) return null;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < prefixSegments.length; i++) {\n const ps = prefixSegments[i];\n if (ps.startsWith(':')) {\n params[ps.slice(1)] = pathSegments[i];\n } else if (ps !== pathSegments[i]) {\n return null;\n }\n }\n\n // Capture the rest as \"*\" param\n const rest = pathSegments.slice(prefixSegments.length).join('/');\n params['*'] = rest;\n return { params };\n }\n\n // Exact segment count required for non-wildcard patterns\n if (pathSegments.length !== patternSegments.length) return null;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i++) {\n const ps = patternSegments[i];\n if (ps.startsWith(':')) {\n params[ps.slice(1)] = pathSegments[i];\n } else if (ps !== pathSegments[i]) {\n return null;\n }\n }\n\n return { params };\n}\n\nfunction matchRoute(\n path: string,\n routes: RouteConfig[],\n): MatchResult | null {\n for (const route of routes) {\n const result = matchSingle(path, route.path);\n if (result) {\n return { pattern: route.path, params: result.params };\n }\n }\n return null;\n}\n\n// ── Router Factory ─────────────────────────────────────────\n\nexport function createRouter(options: RouterOptions): Router {\n const { routes, initialPath } = options;\n\n // Read initial URL\n const initPathRaw = initialPath ?? window.location.pathname;\n const initSearch = initialPath ? '' : window.location.search;\n const initPath = normalizePath(initPathRaw);\n const initQuery = parseQuery(initSearch);\n const initMatch = matchRoute(initPath, routes);\n\n // Create the route store\n const store = createStore<RouteState>({\n state: {\n path: initPath,\n params: initMatch?.params ?? {},\n query: initQuery,\n matched: initMatch?.pattern ?? null,\n },\n actions: {\n _sync: (_: RouteState, payload: RouteState) => payload,\n },\n });\n\n // ── Navigation ──\n\n function buildState(rawPath: string): RouteState {\n const qIdx = rawPath.indexOf('?');\n const pathname = normalizePath(qIdx >= 0 ? rawPath.slice(0, qIdx) : rawPath);\n const queryStr = qIdx >= 0 ? rawPath.slice(qIdx + 1) : '';\n const query = parseQuery(queryStr);\n const match = matchRoute(pathname, routes);\n return {\n path: pathname,\n params: match?.params ?? {},\n query,\n matched: match?.pattern ?? null,\n };\n }\n\n function navigate(path: string): void {\n const state = buildState(path);\n window.history.pushState(null, '', path);\n store.dispatch('_sync', state);\n }\n\n function redirect(path: string): void {\n const state = buildState(path);\n window.history.replaceState(null, '', path);\n store.dispatch('_sync', state);\n }\n\n function back(): void {\n window.history.back();\n }\n\n function forward(): void {\n window.history.forward();\n }\n\n // ── Popstate ──\n\n function onPopState(): void {\n const state = buildState(\n window.location.pathname + window.location.search,\n );\n store.dispatch('_sync', state);\n }\n\n window.addEventListener('popstate', onPopState);\n\n function destroy(): void {\n window.removeEventListener('popstate', onPopState);\n }\n\n // ── Route Component (connected) ──\n\n const Route = connect({\n _path: store.select((s: RouteState) => s.path),\n })(function RouteInner(props: Record<string, any>): VNode | null {\n const { _path, path: pattern, component, children, ...rest } = props;\n const match = matchSingle(_path, pattern);\n if (!match) return null;\n if (component) {\n return h(component, { ...rest, params: match.params });\n }\n return children?.[0] ?? null;\n });\n\n // ── Link Component (plain) ──\n\n function Link(props: Record<string, any>): VNode {\n const { to, children, ...rest } = props;\n return h(\n 'a',\n {\n ...rest,\n href: to,\n onClick: (e: MouseEvent) => {\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;\n e.preventDefault();\n navigate(to);\n },\n },\n ...(children || []),\n );\n }\n\n // ── Redirect Component (plain) ──\n\n function RedirectComponent(props: Record<string, any>): VNode | null {\n redirect(props.to);\n return null;\n }\n\n return {\n store,\n navigate,\n redirect,\n back,\n forward,\n destroy,\n Route,\n Link,\n Redirect: RedirectComponent,\n };\n}\n"],"names":["TEXT_NODE","FRAGMENT","createTextVNode","text","normalizeChild","child","flattenChildren","rawChildren","result","normalized","h","type","props","key","children","createStore","config","state","actions","listeners","getState","dispatch","actionName","payload","action","nextState","listener","subscribe","select","selectorFn","storeObj","pending","queue","scheduleUpdate","callback","flush","batch","flushSync","CONNECTED","connect","bindings","lifecycle","Component","b","ConnectedComponent","selectedProps","propName","store","selector","ComponentInstance","connectedFn","__publicField","parentDom","renderCallback","unsub","cleanup","_a","changed","newValue","shallowEqual","a","keysA","keysB","PATCH","diff","oldVNode","newVNode","patches","propPatches","diffProps","childPatches","diffChildren","oldProps","newProps","set","remove","hasChanges","sameVNode","warnChildKeys","label","seen","keyedCount","unkeyedCount","oldChildren","newChildren","oldStartIdx","oldEndIdx","newStartIdx","newEndIdx","oldStartVNode","oldEndVNode","newStartVNode","newEndVNode","keyMap","i","oldIdx","matchedOld","anchor","createDOMNode","vnode","textNode","frag","el","applyProps","removeProp","setProp","value","oldValue","eventName","prop","applyPatches","patch","dom","newDom","oldDom","_b","_c","roots","render","container","prev","expanded","expand","oldInstances","collectInstances","newInstances","newSet","inst","oldSet","reRenderInstance","instances","instance","childVNode","error","fallbackVNode","c","newExpanded","domParent","unmountSubtree","fallbackExpanded","skip","normalizePath","path","parseQuery","search","cleaned","matchSingle","pattern","normalizedPath","normalizedPattern","pathSegments","patternSegments","prefixSegments","params","ps","rest","matchRoute","routes","route","createRouter","options","initialPath","initPathRaw","initSearch","initPath","initQuery","initMatch","_","buildState","rawPath","qIdx","pathname","queryStr","query","match","navigate","redirect","back","forward","onPopState","destroy","Route","s","_path","component","Link","to","e","RedirectComponent"],"mappings":"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"}