@shane_il/pulse 0.2.0 → 0.4.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/README.md CHANGED
@@ -7,10 +7,12 @@ A render-driven UI framework with virtual DOM and immutable stores. Like React,
7
7
  ## Why Pulse?
8
8
 
9
9
  - **No hooks.** All state lives in external stores. Components are `(props) => VNode`.
10
- - **Stores are first-class.** Create, import, and share stores anywhere. They're framework-agnostic.
10
+ - **Stores are first-class.** Create, import, and share stores anywhere. They're framework-agnostic. Per-component local stores for UI-only state.
11
11
  - **Render-driven.** Describe what the UI looks like for a given state. Pulse handles the rest.
12
12
  - **Built-in routing.** Store-based client-side router — routes are just state.
13
- - **Tiny.** ~5 KB gzipped. Zero runtime dependencies.
13
+ - **Middleware.** Pluggable middleware for logging, action history, and custom logic.
14
+ - **Devtools.** Built-in browser devtools panel — store inspector, action replay, time-travel.
15
+ - **Tiny.** ~6 KB gzipped core, ~9 KB devtools. Zero runtime dependencies.
14
16
 
15
17
  ## Quick Start
16
18
 
@@ -41,7 +43,6 @@ const counterStore = createStore({
41
43
  actions: {
42
44
  increment: (state) => ({ ...state, count: state.count + 1 }),
43
45
  decrement: (state) => ({ ...state, count: state.count - 1 }),
44
- set: (state, value) => ({ ...state, count: value }),
45
46
  },
46
47
  });
47
48
 
@@ -65,186 +66,38 @@ const ConnectedCounter = connect({
65
66
  render(<ConnectedCounter />, document.getElementById('app'));
66
67
  ```
67
68
 
68
- ## API
69
-
70
- ### `createStore({ state, actions })`
71
-
72
- Creates an immutable state store.
73
-
74
- ```js
75
- const store = createStore({
76
- state: { count: 0 },
77
- actions: {
78
- increment: (state) => ({ ...state, count: state.count + 1 }),
79
- set: (state, value) => ({ ...state, count: value }),
80
- },
81
- });
82
-
83
- store.getState(); // { count: 0 }
84
- store.dispatch('increment'); // state is now { count: 1 }
85
- store.dispatch('set', 42); // state is now { count: 42 }
86
-
87
- const unsub = store.subscribe((newState) => {
88
- console.log('State changed:', newState);
89
- });
90
- unsub(); // unsubscribe
91
- ```
92
-
93
- Actions are pure functions: `(state, payload) => newState`. If an action returns the same reference (`===`), subscribers are not notified.
94
-
95
- Stores are standalone — they work outside of Pulse and can be shared across your app.
96
-
97
- ### `connect(bindings, lifecycle?)(Component)`
98
-
99
- Connects a store's state to a component via selectors, with optional lifecycle callbacks.
100
-
101
- ```js
102
- const Connected = connect({
103
- count: counterStore.select((state) => state.count),
104
- name: userStore.select((state) => state.name),
105
- })(MyComponent);
106
- ```
107
-
108
- - Selected values are merged into the component's props.
109
- - Re-renders only when selected values change (shallow equality).
110
- - Subscriptions are automatically managed (mount/unmount).
111
- - Multiple stores can be bound to a single component.
112
-
113
- #### Lifecycle Callbacks
114
-
115
- The optional second argument adds lifecycle hooks:
116
-
117
- ```jsx
118
- const Timer = connect(
119
- { elapsed: timerStore.select((s) => s.elapsed) },
120
- {
121
- onMount: ({ dom, props }) => {
122
- // Called once after first render. DOM element is available.
123
- const id = setInterval(() => timerStore.dispatch('tick'), 1000);
124
- return () => clearInterval(id); // cleanup — called on destroy
125
- },
126
- onUpdate: ({ dom, props }) => {
127
- // Called after every store-driven re-render (not on initial mount).
128
- console.log('Timer updated:', dom.textContent);
129
- },
130
- onDestroy: ({ props }) => {
131
- // Called when component is removed from the DOM.
132
- console.log('Timer removed');
133
- },
134
- onError: ({ error, props }) => {
135
- // Called when the component throws during render. Return fallback VNode.
136
- return h('div', { className: 'error' }, `Error: ${error.message}`);
137
- },
138
- }
139
- )(TimerView);
140
- ```
141
-
142
- - **`onMount({ dom, props })`** — fires once after first render. `dom` is the rendered DOM element. Can return a cleanup function that runs on destroy.
143
- - **`onUpdate({ dom, props })`** — fires after every store-driven re-render (not on initial mount). Useful for DOM measurement, animations, or logging.
144
- - **`onDestroy({ props })`** — fires when the component is removed, after cleanup.
145
- - **`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.
146
- - Re-renders do **not** re-trigger `onMount`.
147
- - For components that only need lifecycle (no store bindings), pass empty bindings: `connect({}, { onMount })(Component)`.
148
-
149
- ### `render(vnode, container)`
150
-
151
- Mounts a virtual DOM tree into a real DOM container. Subsequent calls to `render` with the same container diff and patch.
152
-
153
- ```js
154
- render(<App />, document.getElementById('app'));
155
- ```
156
-
157
- ### `h(type, props, ...children)` / `createElement`
158
-
159
- JSX pragma. You don't call this directly — your JSX compiler transforms `<div>` into `h('div', null)`.
160
-
161
- ### `Fragment`
162
-
163
- Groups children without adding a wrapper DOM node.
164
-
165
- ```jsx
166
- <>
167
- <span>a</span>
168
- <span>b</span>
169
- </>
170
- ```
171
-
172
- ### `createRouter({ routes, initialPath? })`
173
-
174
- Creates a store-based client-side router.
175
-
176
- ```jsx
177
- import { h, createRouter, render } from '@shane_il/pulse';
178
-
179
- const router = createRouter({
180
- routes: [
181
- { path: '/' },
182
- { path: '/users/:id' },
183
- { path: '*' },
184
- ],
185
- });
186
-
187
- const { Route, Link } = router;
188
-
189
- function App() {
190
- return (
191
- <div>
192
- <nav>
193
- <Link to="/">Home</Link>
194
- <Link to="/users/1">User 1</Link>
195
- </nav>
196
- <Route path="/" component={Home} />
197
- <Route path="/users/:id" component={UserProfile} />
198
- <Route path="*" component={NotFound} />
199
- </div>
200
- );
201
- }
69
+ ## How It Works
202
70
 
203
- render(<App />, document.getElementById('app'));
204
71
  ```
205
-
206
- Returns a `Router` object with:
207
-
208
- - **`store`** — a Pulse store holding `{ path, params, query, matched }`. Connect any component to route state.
209
- - **`navigate(path)`** — push a new history entry and update the store.
210
- - **`redirect(path)`** — replace the current history entry (back button skips it).
211
- - **`back()` / `forward()`** — browser history navigation.
212
- - **`Route`** — connected component that renders its `component` prop when the path matches. Passes `params` to the component.
213
- - **`Link`** — renders an `<a>` with SPA navigation on click. Modifier clicks (Ctrl, Cmd) open in a new tab.
214
- - **`Redirect`** — performs a redirect when rendered.
215
- - **`destroy()`** — removes the `popstate` listener (for cleanup in tests).
216
-
217
- Path patterns support static paths (`/about`), dynamic params (`/users/:id`), wildcard suffixes (`/dashboard/*`), and catch-all (`*`).
218
-
219
- ### `flushSync()`
220
-
221
- Synchronously flushes all pending store-triggered re-renders. Primarily useful for testing.
222
-
223
- ```js
224
- store.dispatch('increment');
225
- flushSync();
226
- // DOM is now updated
72
+ Store dispatch → Notify subscribers → Schedule re-render → Expand components
73
+ Diff VDOM Patch DOM (single paint)
227
74
  ```
228
75
 
229
- ## How It Works
230
-
231
76
  1. **Stores** hold immutable state. Actions produce new state via pure functions.
232
77
  2. **`connect()`** subscribes components to store slices via selectors.
233
78
  3. When a store changes, connected components whose selected values differ are scheduled for re-render.
234
79
  4. The **scheduler** batches multiple store updates in the same tick into a single render pass.
235
80
  5. The **VDOM engine** diffs the old and new virtual trees and patches only the changed DOM nodes.
236
81
 
237
- ```
238
- Store dispatch → Notify subscribers → Schedule re-render → Expand components
239
- Diff VDOM Patch DOM (single paint)
240
- ```
82
+ ## Documentation
83
+
84
+ - **[Getting Started](docs/getting-started.md)** installation, JSX setup, first app, project structure
85
+ - **[Stores](docs/stores.md)** — `createStore`, actions, selectors, subscriptions, derived state
86
+ - **[Components](docs/components.md)** — pure components, `connect()`, keyed lists, error boundaries
87
+ - **[Lifecycle](docs/lifecycle.md)** — `onMount`, `onUpdate`, `onDestroy`, `onError`, cleanup functions
88
+ - **[Routing](docs/routing.md)** — `createRouter`, Route/Link/Redirect, path matching, nested routes
89
+ - **[Middleware](docs/middleware.md)** — `logger`, `actionHistory`, `createAsyncAction`, custom middleware
90
+ - **[Devtools](docs/devtools.md)** — browser panel, store inspector, time-travel, component tracking
91
+ - **[Architecture](docs/architecture.md)** — how the VDOM engine works under the hood
241
92
 
242
93
  ## Development
243
94
 
244
95
  ```bash
245
96
  npm install
246
- npm test # run tests (vitest)
247
- npm run build # build dist/ (vite lib mode)
97
+ npm test # 242 tests (vitest)
98
+ npm run typecheck # tsc --noEmit
99
+ npm run lint # eslint
100
+ npm run build # vite lib mode → dist/
248
101
  ```
249
102
 
250
103
  ## License
package/dist/connect.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { VNode, Bindings, Lifecycle, ComponentFunction } from './vnode';
1
+ import type { VNode, Bindings, Lifecycle, ComponentFunction, LocalStoreConfig } from './vnode';
2
2
  export declare const CONNECTED: unique symbol;
3
3
  export declare function __setComponentHooks(onMount: ((instance: ComponentInstance) => void) | null, onUnmount: ((instance: ComponentInstance) => void) | null): void;
4
4
  export declare function connect(bindings: Bindings | null | undefined, lifecycle?: Lifecycle): (Component: ComponentFunction) => {
@@ -14,7 +14,11 @@ export declare class ComponentInstance {
14
14
  parentDom: Node | null;
15
15
  _renderCallback: (() => void) | null;
16
16
  _mountCleanup: (() => void) | null;
17
+ _localState: Record<string, any> | null;
18
+ _localActions: Record<string, (state: any, payload?: any) => any> | null;
17
19
  constructor(connectedFn: ComponentFunction, props: Record<string, any>);
20
+ _initLocalStore(config: LocalStoreConfig): void;
21
+ getLocalProps(): Record<string, any> | null;
18
22
  mount(parentDom: Node, renderCallback: () => void): void;
19
23
  _onStoreChange(): void;
20
24
  updateSelected(): void;
package/dist/devtools.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var ie=Object.defineProperty;var ce=(e,t,n)=>t in e?ie(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var b=(e,t,n)=>ce(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let L=!1;const F=new Set;function le(e){F.add(e),L||(L=!0,queueMicrotask(ae))}function ae(){const e=[...F];F.clear(),L=!1;for(const t of e)t()}const q=Symbol("PULSE_CONNECTED"),A=globalThis;A.__PULSE_HOOKS__||(A.__PULSE_HOOKS__={onMount:null,onUnmount:null});const E=A.__PULSE_HOOKS__;function pe(e,t){E.onMount=e,E.onUnmount=t}function ue(e,t){return function(o){const s=e||{};function r(i){const a={};for(const u in s){const{store:c,selector:h}=s[u];a[u]=h(c.getState())}return o({...a,...i})}return r[q]=!0,r._bindings=s,r._innerComponent=o,r.displayName=`Connected(${o.displayName||o.name||"Anonymous"})`,r}}class fe{constructor(t,n){b(this,"connectedFn");b(this,"props");b(this,"prevSelected");b(this,"unsubscribers");b(this,"lastVTree");b(this,"parentDom");b(this,"_renderCallback");b(this,"_mountCleanup");this.connectedFn=t,this.props=n,this.prevSelected={},this.unsubscribers=[],this.lastVTree=null,this.parentDom=null,this._renderCallback=null,this._mountCleanup=null}mount(t,n){var r;this.parentDom=t,this._renderCallback=n;const o=this.connectedFn._bindings;for(const i in o){const{store:a,selector:u}=o[i];this.prevSelected[i]=u(a.getState())}for(const i in o){const{store:a}=o[i],u=a.subscribe(()=>{this._onStoreChange()});this.unsubscribers.push(u)}const s=this.connectedFn._lifecycle;if(s!=null&&s.onMount){const i=s.onMount({dom:(r=this.lastVTree)==null?void 0:r._dom,props:this.props});typeof i=="function"&&(this._mountCleanup=i)}E.onMount&&E.onMount(this)}_onStoreChange(){const t=this.connectedFn._bindings;let n=!1;for(const o in t){const{store:s,selector:r}=t[o],i=r(s.getState());if(!de(i,this.prevSelected[o])){n=!0;break}}n&&le(this._renderCallback)}updateSelected(){const t=this.connectedFn._bindings;for(const n in t){const{store:o,selector:s}=t[n];this.prevSelected[n]=s(o.getState())}}unmount(){E.onUnmount&&E.onUnmount(this),this._mountCleanup&&(this._mountCleanup(),this._mountCleanup=null);const t=this.connectedFn._lifecycle;t!=null&&t.onDestroy&&t.onDestroy({props:this.props});for(const n of this.unsubscribers)n();this.unsubscribers=[],this._renderCallback=null}}function de(e,t){if(Object.is(e,t))return!0;if(typeof e!="object"||typeof t!="object"||e===null||t===null)return!1;const n=Object.keys(e),o=Object.keys(t);if(n.length!==o.length)return!1;for(const s of n)if(!Object.prototype.hasOwnProperty.call(t,s)||!Object.is(e[s],t[s]))return!1;return!0}function G(e){let t=e.state;const n=e.actions,o=new Set,s=e.middleware;function r(){return t}function i(){for(const f of o)f(t)}function a(f,y){const S=n[f];if(!S)throw new Error(`[pulse] Unknown action: "${f}"`);const x=S(t,y);x!==t&&(t=x,i())}function u(f,y){if(f==="__devtools_replace__"){t=y,i();return}const S=n[f];if(!S)throw new Error(`[pulse] Unknown action: "${f}"`);const x={store:l,actionName:f,payload:y,prevState:t,nextState:void 0};let w=0;function K(){if(w<s.length){const C=s[w++];C(x,K)}else{const C=S(x.prevState,x.payload);x.nextState=C,C!==t&&(t=C,i())}}K()}const c=s&&s.length>0?u:a;function h(f){return o.add(f),()=>{o.delete(f)}}function g(f){return{store:l,selector:f}}const l={getState:r,dispatch:c,subscribe:h,select:g};return e.name&&(l.name=e.name),l}function he(e,t){return(o,s)=>{s(),e.push({actionName:o.actionName,payload:o.payload,prevState:o.prevState,nextState:o.nextState??o.prevState,timestamp:Date.now()}),e.length>1/0&&e.splice(0,e.length-1/0)}}let ye=1;class J{constructor(){b(this,"stores",new Map);b(this,"components",new Map);b(this,"listeners",new Set)}registerStore(t,n,o){const s=o||t.name||`store_${this.stores.size}`;this.stores.set(s,{store:t,history:n,name:s}),t.subscribe(()=>{this.emit({type:"action-dispatched",storeName:s})}),this.emit({type:"store-registered",storeName:s})}getStoreNames(){return Array.from(this.stores.keys())}getStoreState(t){var n;return(n=this.stores.get(t))==null?void 0:n.store.getState()}getTrackedStore(t){return this.stores.get(t)}getHistory(t){var o;if(t)return((o=this.stores.get(t))==null?void 0:o.history)??[];const n=[];for(const s of this.stores.values())n.push(...s.history);return n.sort((s,r)=>s.timestamp-r.timestamp)}trackComponent(t,n){const o=ye++;return this.components.set(o,{id:o,displayName:t,storeNames:n}),this.emit({type:"component-mounted",data:{id:o,displayName:t,storeNames:n}}),o}untrackComponent(t){const n=this.components.get(t);n&&(this.components.delete(t),this.emit({type:"component-unmounted",data:{id:t,displayName:n.displayName}}))}getComponents(){return Array.from(this.components.values())}on(t){return this.listeners.add(t),()=>{this.listeners.delete(t)}}emit(t){for(const n of this.listeners)n(t)}}function me(e,t){const n=[],o=he(n),s=G({...t,middleware:[o,...t.middleware||[]]});return e.registerStore(s,n,t.name),{store:s,history:n}}const H=Symbol("TEXT_NODE"),ge=Symbol("FRAGMENT");function z(e){return{type:H,props:{nodeValue:String(e)},children:[],key:null}}function be(e){return e==null||typeof e=="boolean"?null:typeof e=="string"||typeof e=="number"?z(e):e}function Q(e){const t=[];for(const n of e)if(Array.isArray(n))t.push(...Q(n));else{const o=be(n);o!==null&&t.push(o)}return t}function p(e,t,...n){t=t||{};const o=t.key??null;t.key!==void 0&&(t={...t},delete t.key);const s=Q(n);return{type:e,props:t,children:s,key:o}}const m={CREATE:"CREATE",REMOVE:"REMOVE",REPLACE:"REPLACE",UPDATE:"UPDATE",TEXT:"TEXT",MOVE:"MOVE",CHILDREN:"CHILDREN"};function _(e,t){if(t==null&&e==null)return[];if(t==null)return[{type:m.REMOVE,target:e}];if(e==null)return[{type:m.CREATE,newVNode:t}];if(e.type!==t.type)return[{type:m.REPLACE,oldVNode:e,newVNode:t}];if(t._dom=e._dom,e.type===H)return e.props.nodeValue!==t.props.nodeValue?[{type:m.TEXT,oldVNode:e,newVNode:t}]:[];const n=[],o=Se(e.props,t.props);o&&n.push({type:m.UPDATE,target:e,propPatches:o});const s=xe(e.children,t.children);return s.length&&n.push({type:m.CHILDREN,parent:e,childPatches:s}),n}function Se(e,t){const n={},o=[];let s=!1;for(const r in t)r!=="children"&&e[r]!==t[r]&&(n[r]=t[r],s=!0);for(const r in e)r!=="children"&&(r in t||(o.push(r),s=!0));return s?{set:n,remove:o}:null}function V(e,t){return e==null||t==null?!1:e.type===t.type&&e.key===t.key}function W(e,t){const n=new Set;let o=0,s=0;for(const r of e)r!=null&&(r.key!=null?(o++,n.has(r.key)&&console.warn(`[pulse] Duplicate key "${String(r.key)}" in ${t} children. Keys must be unique among siblings.`),n.add(r.key)):s++);o>0&&s>0&&console.warn(`[pulse] Mixed keyed and unkeyed children in ${t} list (${o} keyed, ${s} unkeyed). Either all children should have keys or none should.`)}function xe(e,t){var g;process.env.NODE_ENV!=="production"&&(W(e,"old"),W(t,"new"));const n=[];let o=0,s=e.length-1,r=0,i=t.length-1,a=e[o],u=e[s],c=t[r],h=t[i];for(;o<=s&&r<=i;){if(a==null){a=e[++o];continue}if(u==null){u=e[--s];continue}if(V(a,c))n.push(..._(a,c)),a=e[++o],c=t[++r];else if(V(u,h))n.push(..._(u,h)),u=e[--s],h=t[--i];else if(V(a,h))n.push({type:m.MOVE,vnode:a,anchor:e[s+1]||null,childPatches:_(a,h)}),a=e[++o],h=t[--i];else if(V(u,c))n.push({type:m.MOVE,vnode:u,anchor:a,childPatches:_(u,c)}),u=e[--s],c=t[++r];else break}if(o<=s&&r<=i){const l=new Map;for(let f=o;f<=s;f++){const y=(g=e[f])==null?void 0:g.key;y!=null&&l.set(y,f)}for(;r<=i;){c=t[r];const f=c.key!=null?l.get(c.key):void 0;if(f!==void 0){const y=e[f];n.push({type:m.MOVE,vnode:y,anchor:e[o]||null,childPatches:_(y,c)}),e[f]=null,l.delete(c.key)}else n.push({type:m.CREATE,newVNode:c,anchor:e[o]||null});r++}for(let f=o;f<=s;f++)e[f]!=null&&n.push({type:m.REMOVE,target:e[f]})}if(o>s){const l=t[i+1]||null;for(let f=r;f<=i;f++)n.push({type:m.CREATE,newVNode:t[f],anchor:l})}else if(r>i)for(let l=o;l<=s;l++)e[l]!=null&&n.push({type:m.REMOVE,target:e[l]});return n}function v(e){if(e.type===H){const n=document.createTextNode(e.props.nodeValue);return e._dom=n,n}if(e.type===ge){const n=document.createDocumentFragment();for(const o of e.children)n.appendChild(v(o));return e._dom=n,n}const t=document.createElement(e.type);_e(t,{},e.props);for(const n of e.children)t.appendChild(v(n));return e._dom=t,t}function _e(e,t,n){for(const o in t)o==="children"||o==="key"||o in n||Z(e,o,t[o]);for(const o in n)o==="children"||o==="key"||t[o]!==n[o]&&Y(e,o,n[o],t[o])}function Y(e,t,n,o){if(t.startsWith("on")){const s=t.slice(2).toLowerCase();o&&e.removeEventListener(s,o),n&&e.addEventListener(s,n)}else if(t==="className")e.className=n||"";else if(t==="style"&&typeof n=="object"){if(typeof o=="object"&&o)for(const s in o)s in n||(e.style[s]="");Object.assign(e.style,n)}else t==="ref"?typeof n=="function"&&n(e):n===!0?e.setAttribute(t,""):n===!1||n==null?e.removeAttribute(t):e.setAttribute(t,n)}function Z(e,t,n){t.startsWith("on")?e.removeEventListener(t.slice(2).toLowerCase(),n):t==="className"?e.className="":e.removeAttribute(t)}function P(e,t){var n,o,s;for(const r of t)switch(r.type){case m.CREATE:{const i=v(r.newVNode);(n=r.anchor)!=null&&n._dom?e.insertBefore(i,r.anchor._dom):e.appendChild(i);break}case m.REMOVE:{const i=r.target._dom;i!=null&&i.parentNode&&i.parentNode.removeChild(i);break}case m.REPLACE:{const i=v(r.newVNode),a=r.oldVNode._dom;a!=null&&a.parentNode&&a.parentNode.replaceChild(i,a);break}case m.UPDATE:{const i=r.target._dom,{set:a,remove:u}=r.propPatches;for(const c of u)Z(i,c,r.target.props[c]);for(const c in a)Y(i,c,a[c],r.target.props[c]);break}case m.TEXT:{const i=r.oldVNode._dom;i&&(i.nodeValue=r.newVNode.props.nodeValue);break}case m.MOVE:{const i=r.vnode._dom;i&&((o=r.anchor)!=null&&o._dom?e.insertBefore(i,r.anchor._dom):e.appendChild(i)),(s=r.childPatches)!=null&&s.length&&i&&P(i,r.childPatches);break}case m.CHILDREN:{const i=r.parent._dom;i&&r.childPatches.length&&P(i,r.childPatches);break}}}const R=new WeakMap;function ke(e,t){const n=R.get(t);if(n){const o=k(e,t),s=[];M(n.vTree,s);const r=_(n.vTree,o);P(t,r);const i=[];o&&M(o,i);const a=new Set(i);for(const c of s)a.has(c)||c.unmount();const u=new Set(s);for(const c of i)u.has(c)||c.mount(t,()=>U(c,t));R.set(t,{vTree:o})}else{const o=k(e,t);if(!o)return;const s=v(o);t.appendChild(s);const r=[];M(o,r);for(const i of r)i.mount(t,()=>U(i,t));R.set(t,{vTree:o})}}function k(e,t){var n;if(e==null)return null;if(typeof e.type=="function"){if(e.type[q]){const s=e.type._lifecycle;try{const r=new fe(e.type,e.props),i=e.type(e.props),u=k(i,t)??z("");if(u._instance){const c={type:"div",props:{style:{display:"contents"}},children:[u],key:e.key};return c._instance=r,r.lastVTree=c,c}return u._instance=r,r.lastVTree=u,u}catch(r){if(s!=null&&s.onError){const i=s.onError({error:r,props:e.props});return k(i,t)}throw r}}const o=e.type({...e.props,children:e.children});return k(o,t)}return(n=e.children)!=null&&n.length&&(e.children=e.children.map(o=>k(o,t)).filter(o=>o!=null)),e}function U(e,t){var s,r;if(!e._renderCallback)return;const n=e.connectedFn,o=n._lifecycle;try{const i=n(e.props);let u=k(i,t)??z(""),c;if(u._instance&&u._instance!==e?(c={type:"div",props:{style:{display:"contents"}},children:[u],key:null},c._instance=e):(u._instance=e,c=u),e.lastVTree){D(e.lastVTree,e);const y=_(e.lastVTree,c),S=((s=e.lastVTree._dom)==null?void 0:s.parentNode)||t;P(S,y),c._dom||(c._dom=e.lastVTree._dom)}const h=[];$(e.lastVTree,h,e);const g=[];$(c,g,e);const l=new Set(g);for(const y of h)l.has(y)||y.unmount();e.lastVTree=c;const f=new Set(h);for(const y of g)f.has(y)||y.mount(t,()=>U(y,t));o!=null&&o.onUpdate&&o.onUpdate({dom:c==null?void 0:c._dom,props:e.props}),e.updateSelected()}catch(i){if(o!=null&&o.onError){const a=o.onError({error:i,props:e.props}),u=k(a,t);if(e.lastVTree&&u){D(e.lastVTree,e);const h=_(e.lastVTree,u),g=((r=e.lastVTree._dom)==null?void 0:r.parentNode)||t;P(g,h),u._dom||(u._dom=e.lastVTree._dom)}const c=[];$(e.lastVTree,c,e);for(const h of c)h.unmount();e.lastVTree=u,e.updateSelected()}else throw i}}function D(e,t){if(!(!e||!e.children))for(let n=0;n<e.children.length;n++){const o=e.children[n];o._instance&&o._instance!==t&&o._instance.lastVTree&&o._instance.lastVTree!==o&&(e.children[n]=o._instance.lastVTree),D(e.children[n],t)}}function M(e,t){if(e&&(e._instance&&t.push(e._instance),e.children))for(const n of e.children)M(n,t)}function $(e,t,n){if(e&&(e._instance&&e._instance!==n&&t.push(e._instance),e.children))for(const o of e.children)$(o,t,n)}function j(e,t,n){const o=e.getTrackedStore(t);if(!o)throw new Error(`[pulse-devtools] Unknown store: "${t}"`);const{store:s,history:r}=o;if(n<0||n>=r.length)throw new Error(`[pulse-devtools] Index ${n} out of range (0..${r.length-1})`);const i=r[n].nextState;s.dispatch("__devtools_replace__",i),e.emit({type:"time-travel",storeName:t,data:{entryIndex:n}})}function Ee(e,t,n){const o=e.getTrackedStore(t);if(!o)throw new Error(`[pulse-devtools] Unknown store: "${t}"`);const{store:s,history:r}=o;if(n<0||n>=r.length)throw new Error(`[pulse-devtools] Index ${n} out of range (0..${r.length-1})`);const i=r.slice(n),a=r[n].prevState;s.dispatch("__devtools_replace__",a);for(const u of i)s.dispatch(u.actionName,u.payload);e.emit({type:"time-travel",storeName:t,data:{replayFrom:n}})}const d={base:"#1e1e2e",surface0:"#313244",surface1:"#45475a",overlay0:"#6c7086",text:"#cdd6f4",subtext0:"#a6adc8",blue:"#89b4fa",green:"#a6e3a1",yellow:"#f9e2af",mauve:"#cba6f7",teal:"#94e2d5",peach:"#fab387"},Te={position:"fixed",bottom:"0",left:"0",right:"0",height:"320px",backgroundColor:d.base,color:d.text,fontFamily:"'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace",fontSize:"12px",lineHeight:"1.5",zIndex:"2147483647",display:"flex",flexDirection:"column",borderTop:`2px solid ${d.mauve}`,overflow:"hidden"},we={display:"flex",alignItems:"center",backgroundColor:d.surface0,borderBottom:`1px solid ${d.surface1}`,padding:"0 8px",height:"32px",flexShrink:"0"},Ce=e=>({background:"none",border:"none",color:e?d.mauve:d.subtext0,fontFamily:"inherit",fontSize:"12px",padding:"6px 12px",cursor:"pointer",borderBottom:e?`2px solid ${d.mauve}`:"2px solid transparent",marginBottom:"-1px"}),Ne={background:"none",border:"none",color:d.overlay0,fontSize:"16px",cursor:"pointer",marginLeft:"auto",padding:"4px 8px",fontFamily:"inherit"},ve={flex:"1",overflow:"auto",padding:"8px 12px"},Pe={display:"flex",height:"100%",gap:"1px"},Oe={width:"200px",flexShrink:"0",borderRight:`1px solid ${d.surface1}`,overflow:"auto",padding:"4px 0"},Ve={flex:"1",overflow:"auto",padding:"8px"},Ie=e=>({padding:"4px 12px",cursor:"pointer",backgroundColor:e?d.surface1:"transparent",color:e?d.blue:d.text}),X={color:d.mauve},I={color:d.green},Me={color:d.yellow},$e={color:d.peach},T={color:d.overlay0,fontStyle:"italic"},Re=e=>({padding:"4px 8px",cursor:"pointer",backgroundColor:e?d.surface1:"transparent",borderLeft:e?`3px solid ${d.blue}`:"3px solid transparent",display:"flex",justifyContent:"space-between",alignItems:"center"}),ee={color:d.blue,fontWeight:"bold"},Le={color:d.overlay0,fontSize:"10px"},Fe={width:"100%",accentColor:d.mauve,margin:"4px 0 8px"},Ae={width:"100%",backgroundColor:d.surface0,border:`1px solid ${d.surface1}`,color:d.text,padding:"4px 8px",fontFamily:"inherit",fontSize:"12px",borderRadius:"4px",outline:"none",marginBottom:"8px",boxSizing:"border-box"},Ue={padding:"4px 8px",borderBottom:`1px solid ${d.surface0}`},De={color:d.teal,fontWeight:"bold"},je={color:d.overlay0,fontSize:"10px",marginLeft:"8px"},te={display:"inline-block",backgroundColor:d.surface1,color:d.subtext0,padding:"1px 6px",borderRadius:"8px",fontSize:"10px",marginLeft:"4px"},Be={color:d.mauve,fontWeight:"bold",fontSize:"12px",marginRight:"8px"};function B(e,t){if(e===null)return p("span",{style:T},"null");if(e===void 0)return p("span",{style:T},"undefined");if(typeof e=="string")return p("span",{style:Me},`"${e}"`);if(typeof e=="boolean")return p("span",{style:$e},String(e));if(typeof e=="number")return p("span",{style:I},String(e));if(Array.isArray(e))return e.length===0?p("span",{style:I},"[]"):t>4?p("span",{style:T},"[…]"):p("div",{style:{paddingLeft:"12px"}},...e.map((n,o)=>p("div",{key:o},p("span",{style:X},`${o}: `),B(n,t+1))));if(typeof e=="object"){const n=Object.keys(e);return n.length===0?p("span",{style:I},"{}"):t>4?p("span",{style:T},"{…}"):p("div",{style:{paddingLeft:"12px"}},...n.map(o=>p("div",{key:o},p("span",{style:X},`${o}: `),B(e[o],t+1))))}return p("span",{style:I},String(e))}function He({storeNames:e,selectedStore:t,storeStates:n,onSelectStore:o}){const s=t?n[t]:null;return p("div",{style:Pe},p("div",{style:Oe},...e.map(r=>p("div",{key:r,style:Ie(r===t),onClick:()=>o(r)},r))),p("div",{style:Ve},t?p("div",null,p("div",{style:{marginBottom:"8px",color:d.subtext0}},"State of ",p("span",{style:ee},t)),s!=null?B(s,0):p("span",{style:T},"No state")):p("span",{style:T},"Select a store")))}function ze(e){const t=new Date(e),n=o=>String(o).padStart(2,"0");return`${n(t.getHours())}:${n(t.getMinutes())}:${n(t.getSeconds())}`}function Ke({actionLog:e,timeTravelIndex:t,filter:n,onFilterChange:o,onTravelTo:s,onSliderChange:r}){const i=n?e.filter(a=>a.actionName.toLowerCase().includes(n.toLowerCase())):e;return p("div",{style:{height:"100%",display:"flex",flexDirection:"column"}},p("input",{style:Ae,placeholder:"Filter actions…",value:n,onInput:a=>o(a.target.value)}),e.length>0?p("div",{style:{flexShrink:"0"}},p("input",{type:"range",style:Fe,min:"0",max:String(e.length-1),value:String(t),onInput:a=>r(Number(a.target.value))}),p("div",{style:{color:d.overlay0,fontSize:"10px",marginBottom:"4px"}},`${t+1} / ${e.length}`)):null,p("div",{style:{flex:"1",overflow:"auto"}},...i.map((a,u)=>{const c=e.indexOf(a);return p("div",{key:c,style:Re(c===t),onClick:()=>s(c)},p("span",null,p("span",{style:ee},a.actionName),a.payload!==void 0?p("span",{style:{color:d.subtext0,marginLeft:"8px"}},typeof a.payload=="object"?JSON.stringify(a.payload):String(a.payload)):null),p("span",{style:Le},ze(a.timestamp)))}),i.length===0?p("div",{style:{color:d.overlay0,padding:"8px"}},e.length===0?"No actions yet":"No matching actions"):null))}function We({components:e}){return e.length===0?p("div",{style:{color:d.overlay0,padding:"8px"}},"No connected components mounted"):p("div",null,...e.map(t=>p("div",{key:t.id,style:Ue},p("span",{style:De},t.displayName),t.storeNames.length>0?p("span",{style:je},t.storeNames.map(n=>p("span",{key:n,style:te},n))):null)))}function Xe(){return G({state:{open:!1,activeTab:"stores",selectedStore:null,timeTravelIndex:-1,storeNames:[],storeStates:{},actionLog:[],filter:"",components:[]},actions:{toggle:e=>({...e,open:!e.open}),open:e=>({...e,open:!0}),close:e=>({...e,open:!1}),setTab:(e,t)=>({...e,activeTab:t}),selectStore:(e,t)=>({...e,selectedStore:t}),setFilter:(e,t)=>({...e,filter:t}),setTimeTravelIndex:(e,t)=>({...e,timeTravelIndex:t}),sync:(e,t)=>({...e,...t})}})}function qe({open:e,activeTab:t,selectedStore:n,timeTravelIndex:o,storeNames:s,storeStates:r,actionLog:i,filter:a,components:u,panelActions:c}){if(!e)return null;const h=[{id:"stores",label:"Stores"},{id:"actions",label:"Actions"},{id:"components",label:"Components"}];let g;return t==="stores"?g=He({storeNames:s,selectedStore:n,storeStates:r,onSelectStore:c.selectStore}):t==="actions"?g=Ke({actionLog:i,timeTravelIndex:o,filter:a,onFilterChange:c.setFilter,onTravelTo:c.travelTo,onSliderChange:c.sliderChange}):g=We({components:u}),p("div",{style:Te},p("div",{style:we},p("span",{key:"title",style:Be},"Pulse"),...h.map(l=>p("button",{key:l.id,style:Ce(l.id===t),onClick:()=>c.setTab(l.id)},l.label)),p("span",{key:"badge",style:te},`${s.length} stores`),p("button",{key:"close",style:Ne,onClick:c.close},"×")),p("div",{style:ve},g))}function Ge(e,t){const n=Xe();t&&t(n);let o=!1;function s(){if(!o){o=!0;try{const l=e.getStoreNames(),f={};for(const w of l)f[w]=e.getStoreState(w);const S=n.getState().selectedStore||l[0]||null,x=S?e.getHistory(S):[];n.dispatch("sync",{storeNames:l,storeStates:f,actionLog:x,timeTravelIndex:x.length>0?x.length-1:-1,selectedStore:S,components:e.getComponents()})}finally{o=!1}}}e.on(l=>{l.type==="component-mounted"||l.type==="component-unmounted"||s()});const r={selectStore:l=>{n.dispatch("selectStore",l);const f=e.getHistory(l);n.dispatch("sync",{actionLog:f,timeTravelIndex:f.length>0?f.length-1:-1})},setTab:l=>n.dispatch("setTab",l),setFilter:l=>n.dispatch("setFilter",l),close:()=>n.dispatch("close"),travelTo:l=>{const f=n.getState().selectedStore;f&&(j(e,f,l),n.dispatch("setTimeTravelIndex",l))},sliderChange:l=>{const f=n.getState().selectedStore;f&&(j(e,f,l),n.dispatch("setTimeTravelIndex",l))}},i=ue({open:n.select(l=>l.open),activeTab:n.select(l=>l.activeTab),selectedStore:n.select(l=>l.selectedStore),timeTravelIndex:n.select(l=>l.timeTravelIndex),storeNames:n.select(l=>l.storeNames),storeStates:n.select(l=>l.storeStates),actionLog:n.select(l=>l.actionLog),filter:n.select(l=>l.filter),components:n.select(l=>l.components)})(l=>qe({...l,panelActions:r}));let a=null;function u(){a||(a=document.createElement("div"),a.id="pulse-devtools-root",document.body.appendChild(a),ke(p(i,null),a),s())}function c(){u(),n.dispatch("open")}function h(){n.dispatch("close")}function g(){u(),n.dispatch("toggle")}return{openPanel:c,closePanel:h,togglePanel:g,panelStore:n}}const O=new J,ne=new WeakSet;function oe(e){ne.add(e)}pe(e=>{const t=e.connectedFn._bindings||{},n=Object.values(t).map(i=>i.store);if(n.length>0&&n.every(i=>ne.has(i)))return;const o=n.map(i=>i.name||"unnamed"),s=e.connectedFn.displayName||"Unknown",r=O.trackComponent(s,o);e._devtoolsId=r},e=>{const t=e._devtoolsId;t!=null&&O.untrackComponent(t)});let N=null;function se(){return N||(N=Ge(O,oe)),N}function Je(){se().openPanel()}function Qe(){N&&N.closePanel()}function re(){se().togglePanel()}typeof window<"u"&&(window.addEventListener("keydown",e=>{e.ctrlKey&&e.shiftKey&&e.key==="P"&&(e.preventDefault(),re())}),window.__PULSE_DEVTOOLS__=O);exports.PulseDevtools=J;exports._markInternalStore=oe;exports.closePanel=Qe;exports.devtools=O;exports.instrumentStore=me;exports.openPanel=Je;exports.replayFrom=Ee;exports.togglePanel=re;exports.travelTo=j;
1
+ "use strict";var at=Object.defineProperty;var pt=(t,e,n)=>e in t?at(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var S=(t,e,n)=>pt(t,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let M=!1;const R=new Set;function G(t){R.add(t),M||(M=!0,queueMicrotask(ut))}function ut(){const t=[...R];R.clear(),M=!1;for(const e of t)e()}const J=Symbol("PULSE_CONNECTED"),F=globalThis;F.__PULSE_HOOKS__||(F.__PULSE_HOOKS__={onMount:null,onUnmount:null});const T=F.__PULSE_HOOKS__;function ft(t,e){T.onMount=t,T.onUnmount=e}function dt(t,e){return function(o){const s=t||{};function r(i){const l={};for(const u in s){const{store:f,selector:h}=s[u];l[u]=h(f.getState())}return o({...l,...i})}return r[J]=!0,r._bindings=s,r._innerComponent=o,r.displayName=`Connected(${o.displayName||o.name||"Anonymous"})`,r}}class ht{constructor(e,n){S(this,"connectedFn");S(this,"props");S(this,"prevSelected");S(this,"unsubscribers");S(this,"lastVTree");S(this,"parentDom");S(this,"_renderCallback");S(this,"_mountCleanup");S(this,"_localState");S(this,"_localActions");this.connectedFn=e,this.props=n,this.prevSelected={},this.unsubscribers=[],this.lastVTree=null,this.parentDom=null,this._renderCallback=null,this._mountCleanup=null,this._localState=null,this._localActions=null;const o=e._lifecycle;o!=null&&o.store&&this._initLocalStore(o.store)}_initLocalStore(e){this._localState={...e.state},this._localActions=e.actions;const n=this.connectedFn._bindings,o=this.connectedFn.displayName||"component",s=Object.keys(this._localState),r=Object.keys(this._localActions);for(const i of s)i in n&&console.warn(`[pulse] Local store state "${i}" shadows global binding in ${o}. Local value will be used.`);for(const i of r)i in n&&console.warn(`[pulse] Local store action "${i}" shadows global binding in ${o}. Local value will be used.`),i in this._localState&&console.warn(`[pulse] Local store action "${i}" shadows state key with same name in ${o}.`)}getLocalProps(){if(!this._localState)return null;const e={...this._localState};for(const n in this._localActions){const o=this._localActions[n];e[n]=s=>{const r=o(this._localState,s);r!==this._localState&&(this._localState=r,this._renderCallback&&G(this._renderCallback))}}return e}mount(e,n){var r;this.parentDom=e,this._renderCallback=n;const o=this.connectedFn._bindings;for(const i in o){const{store:l,selector:u}=o[i];this.prevSelected[i]=u(l.getState())}for(const i in o){const{store:l}=o[i],u=l.subscribe(()=>{this._onStoreChange()});this.unsubscribers.push(u)}const s=this.connectedFn._lifecycle;if(s!=null&&s.onMount){const i=s.onMount({dom:(r=this.lastVTree)==null?void 0:r._dom,props:this.props});typeof i=="function"&&(this._mountCleanup=i)}T.onMount&&T.onMount(this)}_onStoreChange(){const e=this.connectedFn._bindings;let n=!1;for(const o in e){const{store:s,selector:r}=e[o],i=r(s.getState());if(!mt(i,this.prevSelected[o])){n=!0;break}}n&&G(this._renderCallback)}updateSelected(){const e=this.connectedFn._bindings;for(const n in e){const{store:o,selector:s}=e[n];this.prevSelected[n]=s(o.getState())}}unmount(){T.onUnmount&&T.onUnmount(this),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 mt(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),o=Object.keys(e);if(n.length!==o.length)return!1;for(const s of n)if(!Object.prototype.hasOwnProperty.call(e,s)||!Object.is(t[s],e[s]))return!1;return!0}function Q(t){let e=t.state;const n=t.actions,o=new Set,s=t.middleware;function r(){return e}function i(){for(const p of o)p(e)}function l(p,b){const _=n[p];if(!_)throw new Error(`[pulse] Unknown action: "${p}"`);const y=_(e,b);y!==e&&(e=y,i())}function u(p,b){if(p==="__devtools_replace__"){e=b,i();return}const _=n[p];if(!_)throw new Error(`[pulse] Unknown action: "${p}"`);const y={store:c,actionName:p,payload:b,prevState:e,nextState:void 0};let k=0;function K(){if(k<s.length){const C=s[k++];C(y,K)}else{const C=_(y.prevState,y.payload);y.nextState=C,C!==e&&(e=C,i())}}K()}const f=s&&s.length>0?u:l;function h(p){return o.add(p),()=>{o.delete(p)}}function m(p){return{store:c,selector:p}}const c={getState:r,dispatch:f,subscribe:h,select:m};return t.name&&(c.name=t.name),c}function yt(t,e){return(o,s)=>{s(),t.push({actionName:o.actionName,payload:o.payload,prevState:o.prevState,nextState:o.nextState??o.prevState,timestamp:Date.now()}),t.length>1/0&&t.splice(0,t.length-1/0)}}let gt=1;class Y{constructor(){S(this,"stores",new Map);S(this,"components",new Map);S(this,"listeners",new Set)}registerStore(e,n,o){const s=o||e.name||`store_${this.stores.size}`;this.stores.set(s,{store:e,history:n,name:s}),e.subscribe(()=>{this.emit({type:"action-dispatched",storeName:s})}),this.emit({type:"store-registered",storeName:s})}getStoreNames(){return Array.from(this.stores.keys())}getStoreState(e){var n;return(n=this.stores.get(e))==null?void 0:n.store.getState()}getTrackedStore(e){return this.stores.get(e)}getHistory(e){var o;if(e)return((o=this.stores.get(e))==null?void 0:o.history)??[];const n=[];for(const s of this.stores.values())n.push(...s.history);return n.sort((s,r)=>s.timestamp-r.timestamp)}trackComponent(e,n){const o=gt++;return this.components.set(o,{id:o,displayName:e,storeNames:n}),this.emit({type:"component-mounted",data:{id:o,displayName:e,storeNames:n}}),o}untrackComponent(e){const n=this.components.get(e);n&&(this.components.delete(e),this.emit({type:"component-unmounted",data:{id:e,displayName:n.displayName}}))}getComponents(){return Array.from(this.components.values())}on(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}emit(e){for(const n of this.listeners)n(e)}}function St(t,e){const n=[],o=yt(n),s=Q({...e,middleware:[o,...e.middleware||[]]});return t.registerStore(s,n,e.name),{store:s,history:n}}const B=Symbol("TEXT_NODE"),bt=Symbol("FRAGMENT");function z(t){return{type:B,props:{nodeValue:String(t)},children:[],key:null}}function _t(t){return t==null||typeof t=="boolean"?null:typeof t=="string"||typeof t=="number"?z(t):t}function Z(t){const e=[];for(const n of t)if(Array.isArray(n))e.push(...Z(n));else{const o=_t(n);o!==null&&e.push(o)}return e}function a(t,e,...n){e=e||{};const o=e.key??null;e.key!==void 0&&(e={...e},delete e.key);const s=Z(n);return{type:t,props:e,children:s,key:o}}const g={CREATE:"CREATE",REMOVE:"REMOVE",REPLACE:"REPLACE",UPDATE:"UPDATE",TEXT:"TEXT",MOVE:"MOVE",CHILDREN:"CHILDREN"};function x(t,e){if(e==null&&t==null)return[];if(e==null)return[{type:g.REMOVE,target:t}];if(t==null)return[{type:g.CREATE,newVNode:e}];if(t.type!==e.type)return[{type:g.REPLACE,oldVNode:t,newVNode:e}];if(e._dom=t._dom,t.type===B)return t.props.nodeValue!==e.props.nodeValue?[{type:g.TEXT,oldVNode:t,newVNode:e}]:[];const n=[],o=xt(t.props,e.props);o&&n.push({type:g.UPDATE,target:t,propPatches:o});const s=Et(t.children,e.children);return s.length&&n.push({type:g.CHILDREN,parent:t,childPatches:s}),n}function xt(t,e){const n={},o=[];let s=!1;for(const r in e)r!=="children"&&t[r]!==e[r]&&(n[r]=e[r],s=!0);for(const r in t)r!=="children"&&(r in e||(o.push(r),s=!0));return s?{set:n,remove:o}:null}function L(t,e){return t==null||e==null?!1:t.type===e.type&&t.key===e.key}function W(t,e){const n=new Set;let o=0,s=0;for(const r of t)r!=null&&(r.key!=null?(o++,n.has(r.key)&&console.warn(`[pulse] Duplicate key "${String(r.key)}" in ${e} children. Keys must be unique among siblings.`),n.add(r.key)):s++);o>0&&s>0&&console.warn(`[pulse] Mixed keyed and unkeyed children in ${e} list (${o} keyed, ${s} unkeyed). Either all children should have keys or none should.`)}function Et(t,e){var m;process.env.NODE_ENV!=="production"&&(W(t,"old"),W(e,"new"));const n=[];let o=0,s=t.length-1,r=0,i=e.length-1,l=t[o],u=t[s],f=e[r],h=e[i];for(;o<=s&&r<=i;){if(l==null){l=t[++o];continue}if(u==null){u=t[--s];continue}if(L(l,f))n.push(...x(l,f)),l=t[++o],f=e[++r];else if(L(u,h))n.push(...x(u,h)),u=t[--s],h=e[--i];else if(L(l,h))n.push({type:g.MOVE,vnode:l,anchor:t[s+1]||null,childPatches:x(l,h)}),l=t[++o],h=e[--i];else if(L(u,f))n.push({type:g.MOVE,vnode:u,anchor:l,childPatches:x(u,f)}),u=t[--s],f=e[++r];else break}if(o<=s&&r<=i){const c=new Map;for(let p=o;p<=s;p++){const b=(m=t[p])==null?void 0:m.key;b!=null&&c.set(b,p)}for(;r<=i;){f=e[r];const p=f.key!=null?c.get(f.key):void 0;if(p!==void 0){const b=t[p];n.push({type:g.MOVE,vnode:b,anchor:t[o]||null,childPatches:x(b,f)}),t[p]=null,c.delete(f.key)}else n.push({type:g.CREATE,newVNode:f,anchor:t[o]||null});r++}for(let p=o;p<=s;p++)t[p]!=null&&n.push({type:g.REMOVE,target:t[p]})}if(o>s){const c=e[i+1]||null;for(let p=r;p<=i;p++)n.push({type:g.CREATE,newVNode:e[p],anchor:c})}else if(r>i)for(let c=o;c<=s;c++)t[c]!=null&&n.push({type:g.REMOVE,target:t[c]});return n}const tt="http://www.w3.org/2000/svg";function P(t,e){if(t.type===B){const o=document.createTextNode(t.props.nodeValue);return t._dom=o,o}if(t.type===bt){const o=document.createDocumentFragment();for(const s of t.children)o.appendChild(P(s,e));return t._dom=o,o}t.type==="svg"?e=tt:t.type==="foreignObject"&&(e=void 0);const n=e?document.createElementNS(e,t.type):document.createElement(t.type);kt(n,{},t.props);for(const o of t.children)n.appendChild(P(o,e));return t._dom=n,n}function kt(t,e,n){for(const o in e)o==="children"||o==="key"||o in n||nt(t,o,e[o]);for(const o in n)o==="children"||o==="key"||e[o]!==n[o]&&et(t,o,n[o],e[o])}function et(t,e,n,o){if(e.startsWith("on")){const s=e.slice(2).toLowerCase();o&&t.removeEventListener(s,o),n&&t.addEventListener(s,n)}else if(e==="className"||e==="class")t instanceof SVGElement?t.setAttribute("class",n||""):t.className=n||"";else if(e==="style"&&typeof n=="object"){if(typeof o=="object"&&o)for(const s in o)s in n||(t.style[s]="");Object.assign(t.style,n)}else if(e==="dangerouslySetInnerHTML")n&&typeof n.__html=="string"&&(t.innerHTML=n.__html);else if(e==="ref")typeof n=="function"&&n(t);else if(e in t&&!(t instanceof SVGElement))try{t[e]=n??""}catch{t.setAttribute(e,n)}else n===!0?t.setAttribute(e,""):n===!1||n==null?t.removeAttribute(e):t.setAttribute(e,n)}function nt(t,e,n){if(e.startsWith("on"))t.removeEventListener(e.slice(2).toLowerCase(),n);else if(e==="dangerouslySetInnerHTML")t.innerHTML="";else if(e==="className"||e==="class")t instanceof SVGElement?t.removeAttribute("class"):t.className="";else if(e in t&&!(t instanceof SVGElement))try{t[e]=""}catch{t.removeAttribute(e)}else t.removeAttribute(e)}function X(t){return t instanceof SVGElement?tt:void 0}function v(t,e){var n,o,s;for(const r of e)switch(r.type){case g.CREATE:{const i=P(r.newVNode,X(t));(n=r.anchor)!=null&&n._dom?t.insertBefore(i,r.anchor._dom):t.appendChild(i);break}case g.REMOVE:{const i=r.target._dom;i!=null&&i.parentNode&&i.parentNode.removeChild(i);break}case g.REPLACE:{const i=r.oldVNode._dom,l=i==null?void 0:i.parentNode,u=P(r.newVNode,l?X(l):void 0);l&&l.replaceChild(u,i);break}case g.UPDATE:{const i=r.target._dom,{set:l,remove:u}=r.propPatches;for(const f of u)nt(i,f,r.target.props[f]);for(const f in l)et(i,f,l[f],r.target.props[f]);break}case g.TEXT:{const i=r.oldVNode._dom;i&&(i.nodeValue=r.newVNode.props.nodeValue);break}case g.MOVE:{const i=r.vnode._dom;i&&((o=r.anchor)!=null&&o._dom?t.insertBefore(i,r.anchor._dom):t.appendChild(i)),(s=r.childPatches)!=null&&s.length&&i&&v(i,r.childPatches);break}case g.CHILDREN:{const i=r.parent._dom;i&&r.childPatches.length&&v(i,r.childPatches);break}}}const A=new WeakMap;function Tt(t,e){const n=A.get(e);if(n){const o=E(t,e),s=[];I(n.vTree,s);const r=x(n.vTree,o);v(e,r);const i=[];o&&I(o,i);const l=new Set(i);for(const f of s)l.has(f)||f.unmount();const u=new Set(s);for(const f of i)u.has(f)||f.mount(e,()=>U(f,e));A.set(e,{vTree:o})}else{const o=E(t,e);if(!o)return;const s=P(o);e.appendChild(s);const r=[];I(o,r);for(const i of r)i.mount(e,()=>U(i,e));A.set(e,{vTree:o})}}function E(t,e){var n;if(t==null)return null;if(typeof t.type=="function"){if(t.type[J]){const s=t.type._lifecycle;try{const r=new ht(t.type,t.props),i=r.getLocalProps(),l=i?{...t.props,...i}:t.props,u=t.type(l),h=E(u,e)??z("");if(h._instance){const m={type:"div",props:{style:{display:"contents"}},children:[h],key:t.key};return m._instance=r,r.lastVTree=m,m}return h._instance=r,r.lastVTree=h,h}catch(r){if(s!=null&&s.onError){const i=s.onError({error:r,props:t.props});return E(i,e)}throw r}}const o=t.type({...t.props,children:t.children});return E(o,e)}return(n=t.children)!=null&&n.length&&(t.children=t.children.map(o=>E(o,e)).filter(o=>o!=null)),t}function U(t,e){var s,r;if(!t._renderCallback)return;const n=t.connectedFn,o=n._lifecycle;try{const i=t.getLocalProps(),l=i?{...t.props,...i}:t.props,u=n(l),h=E(u,e)??z("");let m;if(h._instance&&h._instance!==t?(m={type:"div",props:{style:{display:"contents"}},children:[h],key:null},m._instance=t):(h._instance=t,m=h),t.lastVTree){j(t.lastVTree,t);const y=x(t.lastVTree,m),k=((s=t.lastVTree._dom)==null?void 0:s.parentNode)||e;v(k,y),m._dom||(m._dom=t.lastVTree._dom)}const c=[];$(t.lastVTree,c,t);const p=[];$(m,p,t);const b=new Set(p);for(const y of c)b.has(y)||y.unmount();t.lastVTree=m;const _=new Set(c);for(const y of p)_.has(y)||y.mount(e,()=>U(y,e));o!=null&&o.onUpdate&&o.onUpdate({dom:m==null?void 0:m._dom,props:t.props}),t.updateSelected()}catch(i){if(o!=null&&o.onError){const l=o.onError({error:i,props:t.props}),u=E(l,e);if(t.lastVTree&&u){j(t.lastVTree,t);const h=x(t.lastVTree,u),m=((r=t.lastVTree._dom)==null?void 0:r.parentNode)||e;v(m,h),u._dom||(u._dom=t.lastVTree._dom)}const f=[];$(t.lastVTree,f,t);for(const h of f)h.unmount();t.lastVTree=u,t.updateSelected()}else throw i}}function j(t,e){if(!(!t||!t.children))for(let n=0;n<t.children.length;n++){const o=t.children[n];o._instance&&o._instance!==e&&o._instance.lastVTree&&o._instance.lastVTree!==o&&(t.children[n]=o._instance.lastVTree),j(t.children[n],e)}}function I(t,e){if(t&&(t._instance&&e.push(t._instance),t.children))for(const n of t.children)I(n,e)}function $(t,e,n){if(t&&(t._instance&&t._instance!==n&&e.push(t._instance),t.children))for(const o of t.children)$(o,e,n)}function H(t,e,n){const o=t.getTrackedStore(e);if(!o)throw new Error(`[pulse-devtools] Unknown store: "${e}"`);const{store:s,history:r}=o;if(n<0||n>=r.length)throw new Error(`[pulse-devtools] Index ${n} out of range (0..${r.length-1})`);const i=r[n].nextState;s.dispatch("__devtools_replace__",i),t.emit({type:"time-travel",storeName:e,data:{entryIndex:n}})}function wt(t,e,n){const o=t.getTrackedStore(e);if(!o)throw new Error(`[pulse-devtools] Unknown store: "${e}"`);const{store:s,history:r}=o;if(n<0||n>=r.length)throw new Error(`[pulse-devtools] Index ${n} out of range (0..${r.length-1})`);const i=r.slice(n),l=r[n].prevState;s.dispatch("__devtools_replace__",l);for(const u of i)s.dispatch(u.actionName,u.payload);t.emit({type:"time-travel",storeName:e,data:{replayFrom:n}})}const d={base:"#1e1e2e",surface0:"#313244",surface1:"#45475a",overlay0:"#6c7086",text:"#cdd6f4",subtext0:"#a6adc8",blue:"#89b4fa",green:"#a6e3a1",yellow:"#f9e2af",mauve:"#cba6f7",teal:"#94e2d5",peach:"#fab387"},Ct={position:"fixed",bottom:"0",left:"0",right:"0",height:"320px",backgroundColor:d.base,color:d.text,fontFamily:"'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace",fontSize:"12px",lineHeight:"1.5",zIndex:"2147483647",display:"flex",flexDirection:"column",borderTop:`2px solid ${d.mauve}`,overflow:"hidden"},Nt={display:"flex",alignItems:"center",backgroundColor:d.surface0,borderBottom:`1px solid ${d.surface1}`,padding:"0 8px",height:"32px",flexShrink:"0"},Pt=t=>({background:"none",border:"none",color:t?d.mauve:d.subtext0,fontFamily:"inherit",fontSize:"12px",padding:"6px 12px",cursor:"pointer",borderBottom:t?`2px solid ${d.mauve}`:"2px solid transparent",marginBottom:"-1px"}),vt={background:"none",border:"none",color:d.overlay0,fontSize:"16px",cursor:"pointer",marginLeft:"auto",padding:"4px 8px",fontFamily:"inherit"},Vt={flex:"1",overflow:"auto",padding:"8px 12px"},Lt={display:"flex",height:"100%",gap:"1px"},Ot={width:"200px",flexShrink:"0",borderRight:`1px solid ${d.surface1}`,overflow:"auto",padding:"4px 0"},It={flex:"1",overflow:"auto",padding:"8px"},$t=t=>({padding:"4px 12px",cursor:"pointer",backgroundColor:t?d.surface1:"transparent",color:t?d.blue:d.text}),q={color:d.mauve},O={color:d.green},At={color:d.yellow},Mt={color:d.peach},w={color:d.overlay0,fontStyle:"italic"},Rt=t=>({padding:"4px 8px",cursor:"pointer",backgroundColor:t?d.surface1:"transparent",borderLeft:t?`3px solid ${d.blue}`:"3px solid transparent",display:"flex",justifyContent:"space-between",alignItems:"center"}),ot={color:d.blue,fontWeight:"bold"},Ft={color:d.overlay0,fontSize:"10px"},Ut={width:"100%",accentColor:d.mauve,margin:"4px 0 8px"},jt={width:"100%",backgroundColor:d.surface0,border:`1px solid ${d.surface1}`,color:d.text,padding:"4px 8px",fontFamily:"inherit",fontSize:"12px",borderRadius:"4px",outline:"none",marginBottom:"8px",boxSizing:"border-box"},Ht={padding:"4px 8px",borderBottom:`1px solid ${d.surface0}`},Dt={color:d.teal,fontWeight:"bold"},Bt={color:d.overlay0,fontSize:"10px",marginLeft:"8px"},st={display:"inline-block",backgroundColor:d.surface1,color:d.subtext0,padding:"1px 6px",borderRadius:"8px",fontSize:"10px",marginLeft:"4px"},zt={color:d.mauve,fontWeight:"bold",fontSize:"12px",marginRight:"8px"};function D(t,e){if(t===null)return a("span",{style:w},"null");if(t===void 0)return a("span",{style:w},"undefined");if(typeof t=="string")return a("span",{style:At},`"${t}"`);if(typeof t=="boolean")return a("span",{style:Mt},String(t));if(typeof t=="number")return a("span",{style:O},String(t));if(Array.isArray(t))return t.length===0?a("span",{style:O},"[]"):e>4?a("span",{style:w},"[…]"):a("div",{style:{paddingLeft:"12px"}},...t.map((n,o)=>a("div",{key:o},a("span",{style:q},`${o}: `),D(n,e+1))));if(typeof t=="object"){const n=Object.keys(t);return n.length===0?a("span",{style:O},"{}"):e>4?a("span",{style:w},"{…}"):a("div",{style:{paddingLeft:"12px"}},...n.map(o=>a("div",{key:o},a("span",{style:q},`${o}: `),D(t[o],e+1))))}return a("span",{style:O},String(t))}function Kt({storeNames:t,selectedStore:e,storeStates:n,onSelectStore:o}){const s=e?n[e]:null;return a("div",{style:Lt},a("div",{style:Ot},...t.map(r=>a("div",{key:r,style:$t(r===e),onClick:()=>o(r)},r))),a("div",{style:It},e?a("div",null,a("div",{style:{marginBottom:"8px",color:d.subtext0}},"State of ",a("span",{style:ot},e)),s!=null?D(s,0):a("span",{style:w},"No state")):a("span",{style:w},"Select a store")))}function Gt(t){const e=new Date(t),n=o=>String(o).padStart(2,"0");return`${n(e.getHours())}:${n(e.getMinutes())}:${n(e.getSeconds())}`}function Wt({actionLog:t,timeTravelIndex:e,filter:n,onFilterChange:o,onTravelTo:s,onSliderChange:r}){const i=n?t.filter(l=>l.actionName.toLowerCase().includes(n.toLowerCase())):t;return a("div",{style:{height:"100%",display:"flex",flexDirection:"column"}},a("input",{style:jt,placeholder:"Filter actions…",value:n,onInput:l=>o(l.target.value)}),t.length>0?a("div",{style:{flexShrink:"0"}},a("input",{type:"range",style:Ut,min:"0",max:String(t.length-1),value:String(e),onInput:l=>r(Number(l.target.value))}),a("div",{style:{color:d.overlay0,fontSize:"10px",marginBottom:"4px"}},`${e+1} / ${t.length}`)):null,a("div",{style:{flex:"1",overflow:"auto"}},...i.map(l=>{const u=t.indexOf(l);return a("div",{key:u,style:Rt(u===e),onClick:()=>s(u)},a("span",null,a("span",{style:ot},l.actionName),l.payload!==void 0?a("span",{style:{color:d.subtext0,marginLeft:"8px"}},typeof l.payload=="object"?JSON.stringify(l.payload):String(l.payload)):null),a("span",{style:Ft},Gt(l.timestamp)))}),i.length===0?a("div",{style:{color:d.overlay0,padding:"8px"}},t.length===0?"No actions yet":"No matching actions"):null))}function Xt({components:t}){return t.length===0?a("div",{style:{color:d.overlay0,padding:"8px"}},"No connected components mounted"):a("div",null,...t.map(e=>a("div",{key:e.id,style:Ht},a("span",{style:Dt},e.displayName),e.storeNames.length>0?a("span",{style:Bt},e.storeNames.map(n=>a("span",{key:n,style:st},n))):null)))}function qt(){return Q({state:{open:!1,activeTab:"stores",selectedStore:null,timeTravelIndex:-1,storeNames:[],storeStates:{},actionLog:[],filter:"",components:[]},actions:{toggle:t=>({...t,open:!t.open}),open:t=>({...t,open:!0}),close:t=>({...t,open:!1}),setTab:(t,e)=>({...t,activeTab:e}),selectStore:(t,e)=>({...t,selectedStore:e}),setFilter:(t,e)=>({...t,filter:e}),setTimeTravelIndex:(t,e)=>({...t,timeTravelIndex:e}),sync:(t,e)=>({...t,...e})}})}function Jt({open:t,activeTab:e,selectedStore:n,timeTravelIndex:o,storeNames:s,storeStates:r,actionLog:i,filter:l,components:u,panelActions:f}){if(!t)return null;const h=[{id:"stores",label:"Stores"},{id:"actions",label:"Actions"},{id:"components",label:"Components"}];let m;return e==="stores"?m=Kt({storeNames:s,selectedStore:n,storeStates:r,onSelectStore:f.selectStore}):e==="actions"?m=Wt({actionLog:i,timeTravelIndex:o,filter:l,onFilterChange:f.setFilter,onTravelTo:f.travelTo,onSliderChange:f.sliderChange}):m=Xt({components:u}),a("div",{style:Ct},a("div",{style:Nt},a("span",{key:"title",style:zt},"Pulse"),...h.map(c=>a("button",{key:c.id,style:Pt(c.id===e),onClick:()=>f.setTab(c.id)},c.label)),a("span",{key:"badge",style:st},`${s.length} stores`),a("button",{key:"close",style:vt,onClick:f.close},"×")),a("div",{style:Vt},m))}function Qt(t,e){const n=qt();e&&e(n);let o=!1;function s(){if(!o){o=!0;try{const c=t.getStoreNames(),p={};for(const k of c)p[k]=t.getStoreState(k);const _=n.getState().selectedStore||c[0]||null,y=_?t.getHistory(_):[];n.dispatch("sync",{storeNames:c,storeStates:p,actionLog:y,timeTravelIndex:y.length>0?y.length-1:-1,selectedStore:_,components:t.getComponents()})}finally{o=!1}}}t.on(c=>{c.type==="component-mounted"||c.type==="component-unmounted"||s()});const r={selectStore:c=>{n.dispatch("selectStore",c);const p=t.getHistory(c);n.dispatch("sync",{actionLog:p,timeTravelIndex:p.length>0?p.length-1:-1})},setTab:c=>n.dispatch("setTab",c),setFilter:c=>n.dispatch("setFilter",c),close:()=>n.dispatch("close"),travelTo:c=>{const p=n.getState().selectedStore;p&&(H(t,p,c),n.dispatch("setTimeTravelIndex",c))},sliderChange:c=>{const p=n.getState().selectedStore;p&&(H(t,p,c),n.dispatch("setTimeTravelIndex",c))}},i=dt({open:n.select(c=>c.open),activeTab:n.select(c=>c.activeTab),selectedStore:n.select(c=>c.selectedStore),timeTravelIndex:n.select(c=>c.timeTravelIndex),storeNames:n.select(c=>c.storeNames),storeStates:n.select(c=>c.storeStates),actionLog:n.select(c=>c.actionLog),filter:n.select(c=>c.filter),components:n.select(c=>c.components)})(c=>Jt({...c,panelActions:r}));let l=null;function u(){l||(l=document.createElement("div"),l.id="pulse-devtools-root",document.body.appendChild(l),Tt(a(i,null),l),s())}function f(){u(),n.dispatch("open")}function h(){n.dispatch("close")}function m(){u(),n.dispatch("toggle")}return{openPanel:f,closePanel:h,togglePanel:m,panelStore:n}}const V=new Y,rt=new WeakSet;function it(t){rt.add(t)}ft(t=>{const e=t.connectedFn._bindings||{},n=Object.values(e).map(i=>i.store);if(n.length>0&&n.every(i=>rt.has(i)))return;const o=n.map(i=>i.name||"unnamed"),s=t.connectedFn.displayName||"Unknown",r=V.trackComponent(s,o);t._devtoolsId=r},t=>{const e=t._devtoolsId;e!=null&&V.untrackComponent(e)});let N=null;function ct(){return N||(N=Qt(V,it)),N}function Yt(){ct().openPanel()}function Zt(){N&&N.closePanel()}function lt(){ct().togglePanel()}typeof window<"u"&&(window.addEventListener("keydown",t=>{t.ctrlKey&&t.shiftKey&&t.key==="P"&&(t.preventDefault(),lt())}),window.__PULSE_DEVTOOLS__=V);exports.PulseDevtools=Y;exports._markInternalStore=it;exports.closePanel=Zt;exports.devtools=V;exports.instrumentStore=St;exports.openPanel=Yt;exports.replayFrom=wt;exports.togglePanel=lt;exports.travelTo=H;
2
2
  //# sourceMappingURL=devtools.cjs.map