@deijose/nix-js 2.0.1 → 2.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/README.md +4 -4
- package/dist/lib/devtools.cjs +1 -1
- package/dist/lib/devtools.js +1 -1
- package/dist/lib/form.cjs +1 -1
- package/dist/lib/form.js +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/nix/form.d.ts +57 -10
- package/dist/lib/nix/index.d.ts +2 -2
- package/dist/lib/nix/router.d.ts +1 -1
- package/dist/lib/nix-js.cjs +1 -1
- package/dist/lib/nix-js.js +1 -1
- package/dist/lib/router.cjs +1 -1
- package/dist/lib/router.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ This is optional: `import { ... } from "@deijose/nix-js"` remains fully supporte
|
|
|
44
44
|
## Quick Start
|
|
45
45
|
|
|
46
46
|
```typescript
|
|
47
|
-
import { signal, html, NixTemplate, NixComponent, mount, createRouter, RouterView, Link,
|
|
47
|
+
import { signal, html, NixTemplate, NixComponent, mount, createRouter, RouterView, Link, nixRouter } from "@deijose/nix-js";
|
|
48
48
|
|
|
49
49
|
// --- Pages as function components (NixTemplate) ---
|
|
50
50
|
// Plain functions returning html`` are recommended for pages and
|
|
@@ -60,7 +60,7 @@ function HomePage(): NixTemplate {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function UserPage(): NixTemplate {
|
|
63
|
-
const router =
|
|
63
|
+
const router = nixRouter();
|
|
64
64
|
return html`<h1>User: ${() => router.params.value.id}</h1>`;
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -112,8 +112,8 @@ Everything ships in a single zero-dependency import:
|
|
|
112
112
|
| **Reactivity** | `signal`, `computed`, `effect`, `batch`, `watch`, `untrack`, `nextTick` |
|
|
113
113
|
| **Templates** | `` html` ` ``, `repeat`, `ref`, `portal`, `transition`, `showWhen` |
|
|
114
114
|
| **Components** | `NixTemplate` (function components), `NixComponent` (lifecycle class), `mount`, children & named slots |
|
|
115
|
-
| **Router** | `createRouter`, `RouterView`, `Link`, `
|
|
116
|
-
| **Forms** | `
|
|
115
|
+
| **Router** | `createRouter`, `RouterView`, `Link`, `nixRouter`, `RouterKey`, guards, nested routes, named routes (`name` + `navigate({ name })`), `mount(..., { router })` |
|
|
116
|
+
| **Forms** | `nixField`, `createForm`, built-in validators, Zod/Valibot interop |
|
|
117
117
|
| **State** | `createStore`, `provide`, `inject`, `createInjectionKey` |
|
|
118
118
|
| **Async** | `suspend` (with `invalidate` for re-fetching), `lazy` |
|
|
119
119
|
| **Error handling** | `createErrorBoundary` |
|
package/dist/lib/devtools.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs"),t=require("./lifecycle.cjs"),n=require("./router.cjs");var r={enabled:!1,activeTab:"signals",renderedTab:null,refreshId:null,root:null,panel:null,content:null,dispose:null,renderKeys:{signals:"",components:"",router:""},scrollMemo:{signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}}},i=new Set,a=new WeakMap,o=1,s=new WeakMap,c=new Map,l=[],u=1;function d(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function f(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function p(e,t){let n=a.get(e);if(n)return n;let r=Date.now(),l={id:o++,createdAt:r,lastUpdated:r,history:[{at:r,value:t}]};return a.set(e,l),i.add(d(e)),l}function m(){let e=[];for(let t of Array.from(i)){let n=t.deref();if(!n){i.delete(t);continue}let o=a.get(n);if(!o)continue;let r=n._subs?.size??0;e.push({id:o.id,value:n.peek(),subscriberCount:r,createdAt:o.createdAt,lastUpdated:o.lastUpdated,history:o.history.slice()})}return e.sort((e,t)=>t.lastUpdated-e.lastUpdated),e}function h(e){let t=e._debugName;if(t&&t.trim())return t;let n=e.constructor;return n?.name&&n.name.trim()?n.name:"AnonymousComponent"}function g(e){let t=e._slots;return t instanceof Map?Array.from(t.keys()).map(e=>String(e)):[]}function _(e){let t={};for(let n of Object.keys(e)){if("__isNixComponent"===n||"children"===n||"_debugName"===n||n.startsWith("_"))continue;let o=e[n];"function"!=typeof o&&(t[n]=o)}return t}function v(e){if(!e)return[];if("*"===e)return["*"];let t=e.split("/").filter(Boolean),n=[],o="";for(let e of t)o+="/"+e,n.push(o);return n.length>0?n:["/"]}function y(){let e=[];for(let[t,n]of c){let o=n.ref.deref();o?(n.debugName=h(o),n.hasDefaultSlot=null!=o.children,n.slotNames=g(o),n.props=_(o),e.push({id:n.id,parentId:n.parentId,debugName:n.debugName,mountedAt:n.mountedAt,hasDefaultSlot:n.hasDefaultSlot,slotNames:[...n.slotNames],props:{...n.props}})):c.delete(t)}return e.sort((e,t)=>e.id-t.id),e}function b(e){let t=[e];for(;t.length>0;){let e=t.pop();for(let[n,o]of c)o.parentId===e&&t.push(n);c.delete(e)}}function x(){i.clear(),a=new WeakMap,o=1,s=new WeakMap,c.clear(),l.length=0,u=1}function S(e){if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e||null==e)return String(e);try{return JSON.stringify(e)}catch{return Object.prototype.toString.call(e)}}function C(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""").replace(/'/g,"'")}function w(e,t=90){let n=S(e);return n.length<=t?n:n.slice(0,t-1)+"…"}function T(e){if(!e)return"-";let t=Date.now()-e;return t<1e3?`${t}ms ago`:t<6e4?`${Math.floor(t/1e3)}s ago`:`${Math.floor(t/6e4)}m ago`}function E(e){let t=m(),n=`${t.length}:${t.map(e=>`${e.id}-${e.lastUpdated}-${e.subscriberCount}`).join("|")}`;if("signals"===r.renderedTab&&r.renderKeys.signals===n)return;r.renderKeys.signals=n,r.renderedTab="signals";let o=t.map(e=>{let t=S(e.value),n=w(e.value,120);return`<tr data-nix-devtools-signal-id="${e.id}">\n <td style="padding:6px 8px;white-space:nowrap;">${e.id}</td>\n <td style="padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;" title="${C(t)}">${C(n)}</td>\n <td>${e.subscriberCount}</td>\n <td>${T(e.lastUpdated)}</td>\n </tr>`}).join("");e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Signals</strong>\n <span style="opacity:.8">${t.length} active</span>\n </div>\n <div data-nix-devtools-scroll="signals" style="max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n <table style="width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;">\n <thead>\n <tr style="background:#1f1f24;">\n <th style="text-align:left;padding:6px 8px;width:42px;">ID</th>\n <th style="text-align:left;padding:6px 8px;">Value</th>\n <th style="text-align:left;padding:6px 8px;width:50px;">Subs</th>\n <th style="text-align:left;padding:6px 8px;width:84px;">Updated</th>\n </tr>\n </thead>\n <tbody>${o}</tbody>\n </table>\n </div>\n <p style="margin:8px 0 0 0;font-size:11px;opacity:.75;">Click a row to log full history in console.</p>\n `;for(let n of e.querySelectorAll("tr[data-nix-devtools-signal-id]"))n.style.cursor="pointer",n.addEventListener("click",()=>{let e=Number(n.dataset.nixDevtoolsSignalId),o=t.find(t=>t.id===e);o&&(console.group(`[Nix DevTools] Signal #${o.id}`),console.log("Current value:",o.value),console.log("Subscribers:",o.subscriberCount),console.table(o.history.map(e=>({at:new Date(e.at).toISOString(),value:e.value}))),console.groupEnd())})}function D(e){let t=new Map,n=[];for(let n of e)t.set(n.id,{...n,children:[]});for(let e of t.values()){if(null==e.parentId){n.push(e);continue}let o=t.get(e.parentId);o?o.children.push(e):n.push(e)}return n}function O(e,t){let n=10+14*t,o=Object.keys(e.props).length>0?S(e.props):"{}",r=e.slotNames.length>0?e.slotNames.join(", "):"none";return`<div style="padding:6px 8px 6px ${n}px;border-bottom:1px solid #24242b;">\n <div><strong>${C(e.debugName)}</strong> <span style="opacity:.7">#${e.id}</span></div>\n <div style="font-size:11px;opacity:.8;">slots: ${r} | default-slot: ${e.hasDefaultSlot?"yes":"no"}</div>\n <div style="font-size:11px;opacity:.8;">props: ${C(w(o,180))}</div>\n </div>`+e.children.map(e=>O(e,t+1)).join("")}function k(e){let t=y(),n=`${t.length}:${t.map(e=>`${e.id}-${e.parentId}-${e.debugName}-${e.hasDefaultSlot}-${e.slotNames.join(",")}-${S(e.props)}`).join("|")}`;if("components"===r.renderedTab&&r.renderKeys.components===n)return;r.renderKeys.components=n,r.renderedTab="components";let o=D(t);e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Component Tree</strong>\n <span style="opacity:.8">${t.length} mounted</span>\n </div>\n <div data-nix-devtools-scroll="components" style="max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n ${o.length>0?o.map(e=>O(e,0)).join(""):"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>"}\n </div>\n `}function A(e){let t=n._debugGetRouterInternal(),o=t?`${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}`:"none";if("router"===r.renderedTab&&r.renderKeys.router===o)return;if(r.renderKeys.router=o,r.renderedTab="router",!t)return void(e.innerHTML='\n <strong>Router State</strong>\n <div style="margin-top:8px;opacity:.75">No active Nix router instance. Ensure your app uses createRouter()/RouterView from @deijose/nix-js/router.</div>\n ');let l=v(t.matchedPath);e.innerHTML=`\n <strong>Router State</strong>\n <div data-nix-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">\n <div><b>mode</b>: ${t.mode}</div>\n <div><b>base</b>: ${t.base}</div>\n <div><b>current</b>: ${C(t.currentPath)}</div>\n <div><b>params</b>: ${C(S(t.params))}</div>\n <div><b>query</b>: ${C(S(t.query))}</div>\n <div><b>matched</b>: ${C(t.matchedPath??"none")}</div>\n <div><b>matched chain</b>: ${l.length>0?C(l.join(" -> ")):"none"}</div>\n <div><b>guards</b>: ${t.activeGuards.names.length>0?C(t.activeGuards.names.join(", ")):"none"}</div>\n </div>\n `}function j(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);t&&(r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft})}function M(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);if(!t)return;let n=r.scrollMemo[e];t.scrollTop=n.top,t.scrollLeft=n.left,"1"!==t.dataset.nixDevtoolsScrollBound&&(t.addEventListener("scroll",()=>{r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft}},{passive:!0}),t.dataset.nixDevtoolsScrollBound="1")}function N(e=!1){if(!r.content)return;let t=r.activeTab;return e||j(t),"signals"===r.activeTab?(E(r.content),void M("signals")):"components"===r.activeTab?(k(r.content),void M("components")):(A(r.content),void M("router"))}function P(){if(r.panel)for(let e of r.panel.querySelectorAll("button[data-nix-devtools-tab]")){let t=e.dataset.nixDevtoolsTab===r.activeTab;e.style.background=t?"#2d4c7a":"#1f1f24"}}function F(e){let t=document.createElement("div");t.setAttribute("data-nix-devtools-root",""),t.style.position="fixed",t.style.zIndex="2147483647",t.style.bottom="16px",t.style.right="bottom-right"===e.position?"16px":"auto",t.style.left="bottom-left"===e.position?"16px":"auto",t.style.fontFamily="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";let n=document.createElement("button");n.type="button",n.textContent="Nix DevTools",n.setAttribute("data-nix-devtools-button",""),n.style.background="#111827",n.style.color="#f9fafb",n.style.border="1px solid #374151",n.style.borderRadius="999px",n.style.padding="8px 12px",n.style.cursor="pointer",n.style.boxShadow="0 6px 18px rgba(0,0,0,.3)";let o=document.createElement("div");o.setAttribute("data-nix-devtools-panel",""),o.style.marginTop="8px",o.style.width="460px",o.style.maxWidth="min(92vw, 460px)",o.style.background="#15151b",o.style.color="#e5e7eb",o.style.border="1px solid #2f2f35",o.style.borderRadius="12px",o.style.padding="10px",o.style.display="none",o.style.boxShadow="0 14px 28px rgba(0,0,0,.35)";let l=document.createElement("div");l.style.display="flex",l.style.gap="6px",l.style.marginBottom="10px";let s=document.createElement("div");s.setAttribute("data-nix-devtools-content","");let a=(e,t)=>{let n=document.createElement("button");return n.type="button",n.textContent=t,n.setAttribute("data-nix-devtools-tab",e),n.style.border="1px solid #353543",n.style.borderRadius="8px",n.style.padding="6px 9px",n.style.background="#1f1f24",n.style.color="#d1d5db",n.style.cursor="pointer",n.addEventListener("click",()=>{r.activeTab=e,P(),N(!0)}),n};l.appendChild(a("signals","Signals")),l.appendChild(a("components","Components")),l.appendChild(a("router","Router")),n.addEventListener("click",()=>{o.style.display="none"===o.style.display?"block":"none","block"===o.style.display&&(P(),N(!0))}),o.appendChild(l),o.appendChild(s),t.appendChild(n),t.appendChild(o),document.body.appendChild(t),r.root=t,r.panel=o,r.content=s}function I(){r.enabled&&(r.enabled=!1,null!=r.refreshId&&(clearInterval(r.refreshId),r.refreshId=null),e._setSignalDebugHooks(null),t._setComponentDebugHooks(null),x(),r.root?.parentNode&&r.root.parentNode.removeChild(r.root),r.root=null,r.panel=null,r.content=null,r.dispose=null,r.renderedTab=null,r.renderKeys={signals:"",components:"",router:""},r.scrollMemo={signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}})}function L(n={}){if(typeof document>"u")return{disable:()=>{}};if(r.enabled&&r.dispose)return{disable:r.dispose};let o=Math.max(100,n.refreshMs??350),a=Math.max(1,n.historyLimit??50),i=n.position??"bottom-right";r.enabled=!0,r.activeTab="signals",e._setSignalDebugHooks({onCreate(e,t){p(e,t)},onWrite(e,t){let n=p(e,t),o=Date.now();n.lastUpdated=o,n.history.push({at:o,value:t}),n.history.length>a&&n.history.splice(0,n.history.length-a)}}),t._setComponentDebugHooks({onMountStart(e){let t=s.get(e);t??(t=u++,s.set(e,t));let n=l.length>0?l[l.length-1]:null;c.set(t,{id:t,parentId:n,debugName:h(e),mountedAt:Date.now(),hasDefaultSlot:null!=e.children,slotNames:g(e),props:_(e),ref:f(e)}),l.push(t)},onMountEnd(e){let t=s.get(e);if(null==t)return;let n=c.get(t);if(n&&(n.debugName=h(e),n.hasDefaultSlot=null!=e.children,n.slotNames=g(e),n.props=_(e)),l[l.length-1]===t)return void l.pop();let o=l.lastIndexOf(t);o>=0&&l.splice(o,1)},onUnmount(e){let t=s.get(e);if(null==t)return;b(t);let n=l.lastIndexOf(t);n>=0&&l.splice(n,1)}}),F({position:i}),r.refreshId=setInterval(()=>{"block"===r.panel?.style.display&&N()},o),n.initiallyOpen&&r.panel&&(r.panel.style.display="block",P(),N(!0));let d=()=>I();return r.dispose=d,{disable:d}}exports.disableDevTools=I,exports.enableDevTools=L;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs"),t=require("./lifecycle.cjs"),n=require("./router.cjs");var r={enabled:!1,activeTab:"signals",renderedTab:null,refreshId:null,root:null,panel:null,content:null,dispose:null,renderKeys:{signals:"",components:"",router:""},scrollMemo:{signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}}},i=new Set,a=new WeakMap,o=1,s=new WeakMap,c=new Map,l=[],u=1;function d(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function f(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function p(e,t){let n=a.get(e);if(n)return n;let r=Date.now(),l={id:o++,createdAt:r,lastUpdated:r,history:[{at:r,value:t}]};return a.set(e,l),i.add(d(e)),l}function m(){let e=[];for(let t of Array.from(i)){let n=t.deref();if(!n){i.delete(t);continue}let o=a.get(n);if(!o)continue;let r=n._subs?.size??0;e.push({id:o.id,value:n.peek(),subscriberCount:r,createdAt:o.createdAt,lastUpdated:o.lastUpdated,history:o.history.slice()})}return e.sort((e,t)=>t.lastUpdated-e.lastUpdated),e}function h(e){let t=e._debugName;if(t&&t.trim())return t;let n=e.constructor;return n?.name&&n.name.trim()?n.name:"AnonymousComponent"}function g(e){let t=e._slots;return t instanceof Map?Array.from(t.keys()).map(e=>String(e)):[]}function _(e){let t={};for(let n of Object.keys(e)){if("__isNixComponent"===n||"children"===n||"_debugName"===n||n.startsWith("_"))continue;let o=e[n];"function"!=typeof o&&(t[n]=o)}return t}function v(e){if(!e)return[];if("*"===e)return["*"];let t=e.split("/").filter(Boolean),n=[],o="";for(let e of t)o+="/"+e,n.push(o);return n.length>0?n:["/"]}function y(){let e=[];for(let[t,n]of c){let o=n.ref.deref();o?(n.debugName=h(o),n.hasDefaultSlot=null!=o.children,n.slotNames=g(o),n.props=_(o),e.push({id:n.id,parentId:n.parentId,debugName:n.debugName,mountedAt:n.mountedAt,hasDefaultSlot:n.hasDefaultSlot,slotNames:[...n.slotNames],props:{...n.props}})):c.delete(t)}return e.sort((e,t)=>e.id-t.id),e}function b(e){let t=[e];for(;t.length>0;){let e=t.pop();for(let[n,o]of c)o.parentId===e&&t.push(n);c.delete(e)}}function x(){i.clear(),a=new WeakMap,o=1,s=new WeakMap,c.clear(),l.length=0,u=1}function S(e){if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e||null==e)return String(e);try{return JSON.stringify(e)}catch{return Object.prototype.toString.call(e)}}function C(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""").replace(/'/g,"'")}function w(e,t=90){let n=S(e);return n.length<=t?n:n.slice(0,t-1)+"…"}function T(e){if(!e)return"-";let t=Date.now()-e;return t<1e3?`${t}ms ago`:t<6e4?`${Math.floor(t/1e3)}s ago`:`${Math.floor(t/6e4)}m ago`}function E(e){let t=m(),n=`${t.length}:${t.map(e=>`${e.id}-${e.lastUpdated}-${e.subscriberCount}`).join("|")}`;if("signals"===r.renderedTab&&r.renderKeys.signals===n)return;r.renderKeys.signals=n,r.renderedTab="signals";let o=t.map(e=>{let t=S(e.value),n=w(e.value,120);return`<tr data-nix-devtools-signal-id="${e.id}">\n <td style="padding:6px 8px;white-space:nowrap;">${e.id}</td>\n <td style="padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;" title="${C(t)}">${C(n)}</td>\n <td>${e.subscriberCount}</td>\n <td>${T(e.lastUpdated)}</td>\n </tr>`}).join("");e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Signals</strong>\n <span style="opacity:.8">${t.length} active</span>\n </div>\n <div data-nix-devtools-scroll="signals" style="max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n <table style="width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;">\n <thead>\n <tr style="background:#1f1f24;">\n <th style="text-align:left;padding:6px 8px;width:42px;">ID</th>\n <th style="text-align:left;padding:6px 8px;">Value</th>\n <th style="text-align:left;padding:6px 8px;width:50px;">Subs</th>\n <th style="text-align:left;padding:6px 8px;width:84px;">Updated</th>\n </tr>\n </thead>\n <tbody>${o}</tbody>\n </table>\n </div>\n <p style="margin:8px 0 0 0;font-size:11px;opacity:.75;">Click a row to log full history in console.</p>\n `;for(let n of e.querySelectorAll("tr[data-nix-devtools-signal-id]"))n.style.cursor="pointer",n.addEventListener("click",()=>{let e=Number(n.dataset.nixDevtoolsSignalId),o=t.find(t=>t.id===e);o&&(console.group(`[Nix DevTools] Signal #${o.id}`),console.log("Current value:",o.value),console.log("Subscribers:",o.subscriberCount),console.table(o.history.map(e=>({at:new Date(e.at).toISOString(),value:e.value}))),console.groupEnd())})}function D(e){let t=new Map,n=[];for(let n of e)t.set(n.id,{...n,children:[]});for(let e of t.values()){if(null==e.parentId){n.push(e);continue}let o=t.get(e.parentId);o?o.children.push(e):n.push(e)}return n}function O(e,t){let n=10+14*t,o=Object.keys(e.props).length>0?S(e.props):"{}",r=e.slotNames.length>0?e.slotNames.join(", "):"none";return`<div style="padding:6px 8px 6px ${n}px;border-bottom:1px solid #24242b;">\n <div><strong>${C(e.debugName)}</strong> <span style="opacity:.7">#${e.id}</span></div>\n <div style="font-size:11px;opacity:.8;">slots: ${r} | default-slot: ${e.hasDefaultSlot?"yes":"no"}</div>\n <div style="font-size:11px;opacity:.8;">props: ${C(w(o,180))}</div>\n </div>`+e.children.map(e=>O(e,t+1)).join("")}function k(e){let t=y(),o=n._debugGetRouterInternal(),l=`${o?`${o.currentPath}|${o.matchedPath??""}`:"no-router"}:${t.length}:${t.map(e=>`${e.id}-${e.parentId}-${e.debugName}-${e.hasDefaultSlot}-${e.slotNames.join(",")}-${S(e.props)}`).join("|")}`;if("components"===r.renderedTab&&r.renderKeys.components===l)return;r.renderKeys.components=l,r.renderedTab="components";let a=D(t);e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Component Tree</strong>\n <span style="opacity:.8">${t.length} mounted</span>\n </div>\n <div style="font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;">\n <span><b>current:</b> ${C(o?.currentPath??"-")}</span>\n <span><b>matched:</b> ${C(o?.matchedPath??"none")}</span>\n </div>\n <div data-nix-devtools-scroll="components" style="max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n ${a.length>0?a.map(e=>O(e,0)).join(""):"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>"}\n </div>\n `}function A(e){let t=n._debugGetRouterInternal(),o=t?`${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}`:"none";if("router"===r.renderedTab&&r.renderKeys.router===o)return;if(r.renderKeys.router=o,r.renderedTab="router",!t)return void(e.innerHTML='\n <strong>Router State</strong>\n <div style="margin-top:8px;opacity:.75">No active Nix router instance. Ensure your app uses createRouter()/RouterView from @deijose/nix-js/router.</div>\n ');let l=v(t.matchedPath);e.innerHTML=`\n <strong>Router State</strong>\n <div data-nix-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">\n <div><b>mode</b>: ${t.mode}</div>\n <div><b>base</b>: ${t.base}</div>\n <div><b>current</b>: ${C(t.currentPath)}</div>\n <div><b>params</b>: ${C(S(t.params))}</div>\n <div><b>query</b>: ${C(S(t.query))}</div>\n <div><b>matched</b>: ${C(t.matchedPath??"none")}</div>\n <div><b>matched chain</b>: ${l.length>0?C(l.join(" -> ")):"none"}</div>\n <div><b>guards</b>: ${t.activeGuards.names.length>0?C(t.activeGuards.names.join(", ")):"none"}</div>\n </div>\n `}function j(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);t&&(r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft})}function M(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);if(!t)return;let n=r.scrollMemo[e];t.scrollTop=n.top,t.scrollLeft=n.left,"1"!==t.dataset.nixDevtoolsScrollBound&&(t.addEventListener("scroll",()=>{r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft}},{passive:!0}),t.dataset.nixDevtoolsScrollBound="1")}function N(e=!1){if(!r.content)return;let t=r.activeTab;return e||j(t),"signals"===r.activeTab?(E(r.content),void M("signals")):"components"===r.activeTab?(k(r.content),void M("components")):(A(r.content),void M("router"))}function P(){if(r.panel)for(let e of r.panel.querySelectorAll("button[data-nix-devtools-tab]")){let t=e.dataset.nixDevtoolsTab===r.activeTab;e.style.background=t?"#2d4c7a":"#1f1f24"}}function F(e){let t=document.createElement("div");t.setAttribute("data-nix-devtools-root",""),t.style.position="fixed",t.style.zIndex="2147483647",t.style.bottom="16px",t.style.right="bottom-right"===e.position?"16px":"auto",t.style.left="bottom-left"===e.position?"16px":"auto",t.style.fontFamily="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";let n=document.createElement("button");n.type="button",n.textContent="Nix DevTools",n.setAttribute("data-nix-devtools-button",""),n.style.background="#111827",n.style.color="#f9fafb",n.style.border="1px solid #374151",n.style.borderRadius="999px",n.style.padding="8px 12px",n.style.cursor="pointer",n.style.boxShadow="0 6px 18px rgba(0,0,0,.3)";let o=document.createElement("div");o.setAttribute("data-nix-devtools-panel",""),o.style.marginTop="8px",o.style.width="460px",o.style.maxWidth="min(92vw, 460px)",o.style.background="#15151b",o.style.color="#e5e7eb",o.style.border="1px solid #2f2f35",o.style.borderRadius="12px",o.style.padding="10px",o.style.display="none",o.style.boxShadow="0 14px 28px rgba(0,0,0,.35)";let l=document.createElement("div");l.style.display="flex",l.style.gap="6px",l.style.marginBottom="10px";let a=document.createElement("div");a.setAttribute("data-nix-devtools-content","");let s=(e,t)=>{let n=document.createElement("button");return n.type="button",n.textContent=t,n.setAttribute("data-nix-devtools-tab",e),n.style.border="1px solid #353543",n.style.borderRadius="8px",n.style.padding="6px 9px",n.style.background="#1f1f24",n.style.color="#d1d5db",n.style.cursor="pointer",n.addEventListener("click",()=>{r.activeTab=e,P(),N(!0)}),n};l.appendChild(s("signals","Signals")),l.appendChild(s("components","Components")),l.appendChild(s("router","Router")),n.addEventListener("click",()=>{o.style.display="none"===o.style.display?"block":"none","block"===o.style.display&&(P(),N(!0))}),o.appendChild(l),o.appendChild(a),t.appendChild(n),t.appendChild(o),document.body.appendChild(t),r.root=t,r.panel=o,r.content=a}function I(){r.enabled&&(r.enabled=!1,null!=r.refreshId&&(clearInterval(r.refreshId),r.refreshId=null),e._setSignalDebugHooks(null),t._setComponentDebugHooks(null),x(),r.root?.parentNode&&r.root.parentNode.removeChild(r.root),r.root=null,r.panel=null,r.content=null,r.dispose=null,r.renderedTab=null,r.renderKeys={signals:"",components:"",router:""},r.scrollMemo={signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}})}function L(n={}){if(typeof document>"u")return{disable:()=>{}};if(r.enabled&&r.dispose)return{disable:r.dispose};let o=Math.max(100,n.refreshMs??350),a=Math.max(1,n.historyLimit??50),i=n.position??"bottom-right";r.enabled=!0,r.activeTab="signals",e._setSignalDebugHooks({onCreate(e,t){p(e,t)},onWrite(e,t){let n=p(e,t),o=Date.now();n.lastUpdated=o,n.history.push({at:o,value:t}),n.history.length>a&&n.history.splice(0,n.history.length-a)}}),t._setComponentDebugHooks({onMountStart(e){let t=s.get(e);t??(t=u++,s.set(e,t));let n=l.length>0?l[l.length-1]:null;c.set(t,{id:t,parentId:n,debugName:h(e),mountedAt:Date.now(),hasDefaultSlot:null!=e.children,slotNames:g(e),props:_(e),ref:f(e)}),l.push(t)},onMountEnd(e){let t=s.get(e);if(null==t)return;let n=c.get(t);if(n&&(n.debugName=h(e),n.hasDefaultSlot=null!=e.children,n.slotNames=g(e),n.props=_(e)),l[l.length-1]===t)return void l.pop();let o=l.lastIndexOf(t);o>=0&&l.splice(o,1)},onUnmount(e){let t=s.get(e);if(null==t)return;b(t);let n=l.lastIndexOf(t);n>=0&&l.splice(n,1)}}),F({position:i}),r.refreshId=setInterval(()=>{"block"===r.panel?.style.display&&N()},o),n.initiallyOpen&&r.panel&&(r.panel.style.display="block",P(),N(!0));let d=()=>I();return r.dispose=d,{disable:d}}exports.disableDevTools=I,exports.enableDevTools=L;
|
package/dist/lib/devtools.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{_setSignalDebugHooks as e}from"./signals.js";import{_setComponentDebugHooks as t}from"./lifecycle.js";import{_debugGetRouterInternal as n}from"./router.js";var r={enabled:!1,activeTab:"signals",renderedTab:null,refreshId:null,root:null,panel:null,content:null,dispose:null,renderKeys:{signals:"",components:"",router:""},scrollMemo:{signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}}},i=new Set,a=new WeakMap,o=1,s=new WeakMap,c=new Map,l=[],u=1;function d(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function f(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function p(e,t){let n=a.get(e);if(n)return n;let r=Date.now(),l={id:o++,createdAt:r,lastUpdated:r,history:[{at:r,value:t}]};return a.set(e,l),i.add(d(e)),l}function m(){let e=[];for(let t of Array.from(i)){let n=t.deref();if(!n){i.delete(t);continue}let o=a.get(n);if(!o)continue;let r=n._subs?.size??0;e.push({id:o.id,value:n.peek(),subscriberCount:r,createdAt:o.createdAt,lastUpdated:o.lastUpdated,history:o.history.slice()})}return e.sort((e,t)=>t.lastUpdated-e.lastUpdated),e}function h(e){let t=e._debugName;if(t&&t.trim())return t;let n=e.constructor;return n?.name&&n.name.trim()?n.name:"AnonymousComponent"}function g(e){let t=e._slots;return t instanceof Map?Array.from(t.keys()).map(e=>String(e)):[]}function _(e){let t={};for(let n of Object.keys(e)){if("__isNixComponent"===n||"children"===n||"_debugName"===n||n.startsWith("_"))continue;let o=e[n];"function"!=typeof o&&(t[n]=o)}return t}function v(e){if(!e)return[];if("*"===e)return["*"];let t=e.split("/").filter(Boolean),n=[],o="";for(let e of t)o+="/"+e,n.push(o);return n.length>0?n:["/"]}function y(){let e=[];for(let[t,n]of c){let o=n.ref.deref();o?(n.debugName=h(o),n.hasDefaultSlot=null!=o.children,n.slotNames=g(o),n.props=_(o),e.push({id:n.id,parentId:n.parentId,debugName:n.debugName,mountedAt:n.mountedAt,hasDefaultSlot:n.hasDefaultSlot,slotNames:[...n.slotNames],props:{...n.props}})):c.delete(t)}return e.sort((e,t)=>e.id-t.id),e}function b(e){let t=[e];for(;t.length>0;){let e=t.pop();for(let[n,o]of c)o.parentId===e&&t.push(n);c.delete(e)}}function x(){i.clear(),a=new WeakMap,o=1,s=new WeakMap,c.clear(),l.length=0,u=1}function S(e){if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e||null==e)return String(e);try{return JSON.stringify(e)}catch{return Object.prototype.toString.call(e)}}function C(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""").replace(/'/g,"'")}function w(e,t=90){let n=S(e);return n.length<=t?n:n.slice(0,t-1)+"…"}function T(e){if(!e)return"-";let t=Date.now()-e;return t<1e3?`${t}ms ago`:t<6e4?`${Math.floor(t/1e3)}s ago`:`${Math.floor(t/6e4)}m ago`}function E(e){let t=m(),n=`${t.length}:${t.map(e=>`${e.id}-${e.lastUpdated}-${e.subscriberCount}`).join("|")}`;if("signals"===r.renderedTab&&r.renderKeys.signals===n)return;r.renderKeys.signals=n,r.renderedTab="signals";let o=t.map(e=>{let t=S(e.value),n=w(e.value,120);return`<tr data-nix-devtools-signal-id="${e.id}">\n <td style="padding:6px 8px;white-space:nowrap;">${e.id}</td>\n <td style="padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;" title="${C(t)}">${C(n)}</td>\n <td>${e.subscriberCount}</td>\n <td>${T(e.lastUpdated)}</td>\n </tr>`}).join("");e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Signals</strong>\n <span style="opacity:.8">${t.length} active</span>\n </div>\n <div data-nix-devtools-scroll="signals" style="max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n <table style="width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;">\n <thead>\n <tr style="background:#1f1f24;">\n <th style="text-align:left;padding:6px 8px;width:42px;">ID</th>\n <th style="text-align:left;padding:6px 8px;">Value</th>\n <th style="text-align:left;padding:6px 8px;width:50px;">Subs</th>\n <th style="text-align:left;padding:6px 8px;width:84px;">Updated</th>\n </tr>\n </thead>\n <tbody>${o}</tbody>\n </table>\n </div>\n <p style="margin:8px 0 0 0;font-size:11px;opacity:.75;">Click a row to log full history in console.</p>\n `;for(let n of e.querySelectorAll("tr[data-nix-devtools-signal-id]"))n.style.cursor="pointer",n.addEventListener("click",()=>{let e=Number(n.dataset.nixDevtoolsSignalId),o=t.find(t=>t.id===e);o&&(console.group(`[Nix DevTools] Signal #${o.id}`),console.log("Current value:",o.value),console.log("Subscribers:",o.subscriberCount),console.table(o.history.map(e=>({at:new Date(e.at).toISOString(),value:e.value}))),console.groupEnd())})}function D(e){let t=new Map,n=[];for(let n of e)t.set(n.id,{...n,children:[]});for(let e of t.values()){if(null==e.parentId){n.push(e);continue}let o=t.get(e.parentId);o?o.children.push(e):n.push(e)}return n}function O(e,t){let n=10+14*t,o=Object.keys(e.props).length>0?S(e.props):"{}",r=e.slotNames.length>0?e.slotNames.join(", "):"none";return`<div style="padding:6px 8px 6px ${n}px;border-bottom:1px solid #24242b;">\n <div><strong>${C(e.debugName)}</strong> <span style="opacity:.7">#${e.id}</span></div>\n <div style="font-size:11px;opacity:.8;">slots: ${r} | default-slot: ${e.hasDefaultSlot?"yes":"no"}</div>\n <div style="font-size:11px;opacity:.8;">props: ${C(w(o,180))}</div>\n </div>`+e.children.map(e=>O(e,t+1)).join("")}function k(e){let t=y(),n=`${t.length}:${t.map(e=>`${e.id}-${e.parentId}-${e.debugName}-${e.hasDefaultSlot}-${e.slotNames.join(",")}-${S(e.props)}`).join("|")}`;if("components"===r.renderedTab&&r.renderKeys.components===n)return;r.renderKeys.components=n,r.renderedTab="components";let o=D(t);e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Component Tree</strong>\n <span style="opacity:.8">${t.length} mounted</span>\n </div>\n <div data-nix-devtools-scroll="components" style="max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n ${o.length>0?o.map(e=>O(e,0)).join(""):"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>"}\n </div>\n `}function A(e){let t=n(),o=t?`${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}`:"none";if("router"===r.renderedTab&&r.renderKeys.router===o)return;if(r.renderKeys.router=o,r.renderedTab="router",!t)return void(e.innerHTML='\n <strong>Router State</strong>\n <div style="margin-top:8px;opacity:.75">No active Nix router instance. Ensure your app uses createRouter()/RouterView from @deijose/nix-js/router.</div>\n ');let l=v(t.matchedPath);e.innerHTML=`\n <strong>Router State</strong>\n <div data-nix-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">\n <div><b>mode</b>: ${t.mode}</div>\n <div><b>base</b>: ${t.base}</div>\n <div><b>current</b>: ${C(t.currentPath)}</div>\n <div><b>params</b>: ${C(S(t.params))}</div>\n <div><b>query</b>: ${C(S(t.query))}</div>\n <div><b>matched</b>: ${C(t.matchedPath??"none")}</div>\n <div><b>matched chain</b>: ${l.length>0?C(l.join(" -> ")):"none"}</div>\n <div><b>guards</b>: ${t.activeGuards.names.length>0?C(t.activeGuards.names.join(", ")):"none"}</div>\n </div>\n `}function j(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);t&&(r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft})}function M(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);if(!t)return;let n=r.scrollMemo[e];t.scrollTop=n.top,t.scrollLeft=n.left,"1"!==t.dataset.nixDevtoolsScrollBound&&(t.addEventListener("scroll",()=>{r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft}},{passive:!0}),t.dataset.nixDevtoolsScrollBound="1")}function N(e=!1){if(!r.content)return;let t=r.activeTab;return e||j(t),"signals"===r.activeTab?(E(r.content),void M("signals")):"components"===r.activeTab?(k(r.content),void M("components")):(A(r.content),void M("router"))}function P(){if(r.panel)for(let e of r.panel.querySelectorAll("button[data-nix-devtools-tab]")){let t=e.dataset.nixDevtoolsTab===r.activeTab;e.style.background=t?"#2d4c7a":"#1f1f24"}}function F(e){let t=document.createElement("div");t.setAttribute("data-nix-devtools-root",""),t.style.position="fixed",t.style.zIndex="2147483647",t.style.bottom="16px",t.style.right="bottom-right"===e.position?"16px":"auto",t.style.left="bottom-left"===e.position?"16px":"auto",t.style.fontFamily="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";let n=document.createElement("button");n.type="button",n.textContent="Nix DevTools",n.setAttribute("data-nix-devtools-button",""),n.style.background="#111827",n.style.color="#f9fafb",n.style.border="1px solid #374151",n.style.borderRadius="999px",n.style.padding="8px 12px",n.style.cursor="pointer",n.style.boxShadow="0 6px 18px rgba(0,0,0,.3)";let o=document.createElement("div");o.setAttribute("data-nix-devtools-panel",""),o.style.marginTop="8px",o.style.width="460px",o.style.maxWidth="min(92vw, 460px)",o.style.background="#15151b",o.style.color="#e5e7eb",o.style.border="1px solid #2f2f35",o.style.borderRadius="12px",o.style.padding="10px",o.style.display="none",o.style.boxShadow="0 14px 28px rgba(0,0,0,.35)";let l=document.createElement("div");l.style.display="flex",l.style.gap="6px",l.style.marginBottom="10px";let s=document.createElement("div");s.setAttribute("data-nix-devtools-content","");let a=(e,t)=>{let n=document.createElement("button");return n.type="button",n.textContent=t,n.setAttribute("data-nix-devtools-tab",e),n.style.border="1px solid #353543",n.style.borderRadius="8px",n.style.padding="6px 9px",n.style.background="#1f1f24",n.style.color="#d1d5db",n.style.cursor="pointer",n.addEventListener("click",()=>{r.activeTab=e,P(),N(!0)}),n};l.appendChild(a("signals","Signals")),l.appendChild(a("components","Components")),l.appendChild(a("router","Router")),n.addEventListener("click",()=>{o.style.display="none"===o.style.display?"block":"none","block"===o.style.display&&(P(),N(!0))}),o.appendChild(l),o.appendChild(s),t.appendChild(n),t.appendChild(o),document.body.appendChild(t),r.root=t,r.panel=o,r.content=s}function I(){r.enabled&&(r.enabled=!1,null!=r.refreshId&&(clearInterval(r.refreshId),r.refreshId=null),e(null),t(null),x(),r.root?.parentNode&&r.root.parentNode.removeChild(r.root),r.root=null,r.panel=null,r.content=null,r.dispose=null,r.renderedTab=null,r.renderKeys={signals:"",components:"",router:""},r.scrollMemo={signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}})}function L(n={}){if(typeof document>"u")return{disable:()=>{}};if(r.enabled&&r.dispose)return{disable:r.dispose};let o=Math.max(100,n.refreshMs??350),a=Math.max(1,n.historyLimit??50),i=n.position??"bottom-right";r.enabled=!0,r.activeTab="signals",e({onCreate(e,t){p(e,t)},onWrite(e,t){let n=p(e,t),o=Date.now();n.lastUpdated=o,n.history.push({at:o,value:t}),n.history.length>a&&n.history.splice(0,n.history.length-a)}}),t({onMountStart(e){let t=s.get(e);t??(t=u++,s.set(e,t));let n=l.length>0?l[l.length-1]:null;c.set(t,{id:t,parentId:n,debugName:h(e),mountedAt:Date.now(),hasDefaultSlot:null!=e.children,slotNames:g(e),props:_(e),ref:f(e)}),l.push(t)},onMountEnd(e){let t=s.get(e);if(null==t)return;let n=c.get(t);if(n&&(n.debugName=h(e),n.hasDefaultSlot=null!=e.children,n.slotNames=g(e),n.props=_(e)),l[l.length-1]===t)return void l.pop();let o=l.lastIndexOf(t);o>=0&&l.splice(o,1)},onUnmount(e){let t=s.get(e);if(null==t)return;b(t);let n=l.lastIndexOf(t);n>=0&&l.splice(n,1)}}),F({position:i}),r.refreshId=setInterval(()=>{"block"===r.panel?.style.display&&N()},o),n.initiallyOpen&&r.panel&&(r.panel.style.display="block",P(),N(!0));let d=()=>I();return r.dispose=d,{disable:d}}export{I as disableDevTools,L as enableDevTools};
|
|
1
|
+
import{_setSignalDebugHooks as e}from"./signals.js";import{_setComponentDebugHooks as t}from"./lifecycle.js";import{_debugGetRouterInternal as n}from"./router.js";var r={enabled:!1,activeTab:"signals",renderedTab:null,refreshId:null,root:null,panel:null,content:null,dispose:null,renderKeys:{signals:"",components:"",router:""},scrollMemo:{signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}}},i=new Set,a=new WeakMap,o=1,s=new WeakMap,c=new Map,l=[],u=1;function d(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function f(e){return typeof WeakRef<"u"?new WeakRef(e):{deref:()=>e}}function p(e,t){let n=a.get(e);if(n)return n;let r=Date.now(),l={id:o++,createdAt:r,lastUpdated:r,history:[{at:r,value:t}]};return a.set(e,l),i.add(d(e)),l}function m(){let e=[];for(let t of Array.from(i)){let n=t.deref();if(!n){i.delete(t);continue}let o=a.get(n);if(!o)continue;let r=n._subs?.size??0;e.push({id:o.id,value:n.peek(),subscriberCount:r,createdAt:o.createdAt,lastUpdated:o.lastUpdated,history:o.history.slice()})}return e.sort((e,t)=>t.lastUpdated-e.lastUpdated),e}function h(e){let t=e._debugName;if(t&&t.trim())return t;let n=e.constructor;return n?.name&&n.name.trim()?n.name:"AnonymousComponent"}function g(e){let t=e._slots;return t instanceof Map?Array.from(t.keys()).map(e=>String(e)):[]}function _(e){let t={};for(let n of Object.keys(e)){if("__isNixComponent"===n||"children"===n||"_debugName"===n||n.startsWith("_"))continue;let o=e[n];"function"!=typeof o&&(t[n]=o)}return t}function v(e){if(!e)return[];if("*"===e)return["*"];let t=e.split("/").filter(Boolean),n=[],o="";for(let e of t)o+="/"+e,n.push(o);return n.length>0?n:["/"]}function y(){let e=[];for(let[t,n]of c){let o=n.ref.deref();o?(n.debugName=h(o),n.hasDefaultSlot=null!=o.children,n.slotNames=g(o),n.props=_(o),e.push({id:n.id,parentId:n.parentId,debugName:n.debugName,mountedAt:n.mountedAt,hasDefaultSlot:n.hasDefaultSlot,slotNames:[...n.slotNames],props:{...n.props}})):c.delete(t)}return e.sort((e,t)=>e.id-t.id),e}function b(e){let t=[e];for(;t.length>0;){let e=t.pop();for(let[n,o]of c)o.parentId===e&&t.push(n);c.delete(e)}}function x(){i.clear(),a=new WeakMap,o=1,s=new WeakMap,c.clear(),l.length=0,u=1}function S(e){if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e||null==e)return String(e);try{return JSON.stringify(e)}catch{return Object.prototype.toString.call(e)}}function C(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/\"/g,""").replace(/'/g,"'")}function w(e,t=90){let n=S(e);return n.length<=t?n:n.slice(0,t-1)+"…"}function T(e){if(!e)return"-";let t=Date.now()-e;return t<1e3?`${t}ms ago`:t<6e4?`${Math.floor(t/1e3)}s ago`:`${Math.floor(t/6e4)}m ago`}function E(e){let t=m(),n=`${t.length}:${t.map(e=>`${e.id}-${e.lastUpdated}-${e.subscriberCount}`).join("|")}`;if("signals"===r.renderedTab&&r.renderKeys.signals===n)return;r.renderKeys.signals=n,r.renderedTab="signals";let o=t.map(e=>{let t=S(e.value),n=w(e.value,120);return`<tr data-nix-devtools-signal-id="${e.id}">\n <td style="padding:6px 8px;white-space:nowrap;">${e.id}</td>\n <td style="padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;" title="${C(t)}">${C(n)}</td>\n <td>${e.subscriberCount}</td>\n <td>${T(e.lastUpdated)}</td>\n </tr>`}).join("");e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Signals</strong>\n <span style="opacity:.8">${t.length} active</span>\n </div>\n <div data-nix-devtools-scroll="signals" style="max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n <table style="width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;">\n <thead>\n <tr style="background:#1f1f24;">\n <th style="text-align:left;padding:6px 8px;width:42px;">ID</th>\n <th style="text-align:left;padding:6px 8px;">Value</th>\n <th style="text-align:left;padding:6px 8px;width:50px;">Subs</th>\n <th style="text-align:left;padding:6px 8px;width:84px;">Updated</th>\n </tr>\n </thead>\n <tbody>${o}</tbody>\n </table>\n </div>\n <p style="margin:8px 0 0 0;font-size:11px;opacity:.75;">Click a row to log full history in console.</p>\n `;for(let n of e.querySelectorAll("tr[data-nix-devtools-signal-id]"))n.style.cursor="pointer",n.addEventListener("click",()=>{let e=Number(n.dataset.nixDevtoolsSignalId),o=t.find(t=>t.id===e);o&&(console.group(`[Nix DevTools] Signal #${o.id}`),console.log("Current value:",o.value),console.log("Subscribers:",o.subscriberCount),console.table(o.history.map(e=>({at:new Date(e.at).toISOString(),value:e.value}))),console.groupEnd())})}function D(e){let t=new Map,n=[];for(let n of e)t.set(n.id,{...n,children:[]});for(let e of t.values()){if(null==e.parentId){n.push(e);continue}let o=t.get(e.parentId);o?o.children.push(e):n.push(e)}return n}function O(e,t){let n=10+14*t,o=Object.keys(e.props).length>0?S(e.props):"{}",r=e.slotNames.length>0?e.slotNames.join(", "):"none";return`<div style="padding:6px 8px 6px ${n}px;border-bottom:1px solid #24242b;">\n <div><strong>${C(e.debugName)}</strong> <span style="opacity:.7">#${e.id}</span></div>\n <div style="font-size:11px;opacity:.8;">slots: ${r} | default-slot: ${e.hasDefaultSlot?"yes":"no"}</div>\n <div style="font-size:11px;opacity:.8;">props: ${C(w(o,180))}</div>\n </div>`+e.children.map(e=>O(e,t+1)).join("")}function k(e){let t=y(),o=n(),l=`${o?`${o.currentPath}|${o.matchedPath??""}`:"no-router"}:${t.length}:${t.map(e=>`${e.id}-${e.parentId}-${e.debugName}-${e.hasDefaultSlot}-${e.slotNames.join(",")}-${S(e.props)}`).join("|")}`;if("components"===r.renderedTab&&r.renderKeys.components===l)return;r.renderKeys.components=l,r.renderedTab="components";let a=D(t);e.innerHTML=`\n <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">\n <strong>Component Tree</strong>\n <span style="opacity:.8">${t.length} mounted</span>\n </div>\n <div style="font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;">\n <span><b>current:</b> ${C(o?.currentPath??"-")}</span>\n <span><b>matched:</b> ${C(o?.matchedPath??"none")}</span>\n </div>\n <div data-nix-devtools-scroll="components" style="max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;">\n ${a.length>0?a.map(e=>O(e,0)).join(""):"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>"}\n </div>\n `}function A(e){let t=n(),o=t?`${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}`:"none";if("router"===r.renderedTab&&r.renderKeys.router===o)return;if(r.renderKeys.router=o,r.renderedTab="router",!t)return void(e.innerHTML='\n <strong>Router State</strong>\n <div style="margin-top:8px;opacity:.75">No active Nix router instance. Ensure your app uses createRouter()/RouterView from @deijose/nix-js/router.</div>\n ');let l=v(t.matchedPath);e.innerHTML=`\n <strong>Router State</strong>\n <div data-nix-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">\n <div><b>mode</b>: ${t.mode}</div>\n <div><b>base</b>: ${t.base}</div>\n <div><b>current</b>: ${C(t.currentPath)}</div>\n <div><b>params</b>: ${C(S(t.params))}</div>\n <div><b>query</b>: ${C(S(t.query))}</div>\n <div><b>matched</b>: ${C(t.matchedPath??"none")}</div>\n <div><b>matched chain</b>: ${l.length>0?C(l.join(" -> ")):"none"}</div>\n <div><b>guards</b>: ${t.activeGuards.names.length>0?C(t.activeGuards.names.join(", ")):"none"}</div>\n </div>\n `}function j(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);t&&(r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft})}function M(e){if(!r.content)return;let t=r.content.querySelector(`[data-nix-devtools-scroll='${e}']`);if(!t)return;let n=r.scrollMemo[e];t.scrollTop=n.top,t.scrollLeft=n.left,"1"!==t.dataset.nixDevtoolsScrollBound&&(t.addEventListener("scroll",()=>{r.scrollMemo[e]={top:t.scrollTop,left:t.scrollLeft}},{passive:!0}),t.dataset.nixDevtoolsScrollBound="1")}function N(e=!1){if(!r.content)return;let t=r.activeTab;return e||j(t),"signals"===r.activeTab?(E(r.content),void M("signals")):"components"===r.activeTab?(k(r.content),void M("components")):(A(r.content),void M("router"))}function P(){if(r.panel)for(let e of r.panel.querySelectorAll("button[data-nix-devtools-tab]")){let t=e.dataset.nixDevtoolsTab===r.activeTab;e.style.background=t?"#2d4c7a":"#1f1f24"}}function F(e){let t=document.createElement("div");t.setAttribute("data-nix-devtools-root",""),t.style.position="fixed",t.style.zIndex="2147483647",t.style.bottom="16px",t.style.right="bottom-right"===e.position?"16px":"auto",t.style.left="bottom-left"===e.position?"16px":"auto",t.style.fontFamily="ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";let n=document.createElement("button");n.type="button",n.textContent="Nix DevTools",n.setAttribute("data-nix-devtools-button",""),n.style.background="#111827",n.style.color="#f9fafb",n.style.border="1px solid #374151",n.style.borderRadius="999px",n.style.padding="8px 12px",n.style.cursor="pointer",n.style.boxShadow="0 6px 18px rgba(0,0,0,.3)";let o=document.createElement("div");o.setAttribute("data-nix-devtools-panel",""),o.style.marginTop="8px",o.style.width="460px",o.style.maxWidth="min(92vw, 460px)",o.style.background="#15151b",o.style.color="#e5e7eb",o.style.border="1px solid #2f2f35",o.style.borderRadius="12px",o.style.padding="10px",o.style.display="none",o.style.boxShadow="0 14px 28px rgba(0,0,0,.35)";let l=document.createElement("div");l.style.display="flex",l.style.gap="6px",l.style.marginBottom="10px";let a=document.createElement("div");a.setAttribute("data-nix-devtools-content","");let s=(e,t)=>{let n=document.createElement("button");return n.type="button",n.textContent=t,n.setAttribute("data-nix-devtools-tab",e),n.style.border="1px solid #353543",n.style.borderRadius="8px",n.style.padding="6px 9px",n.style.background="#1f1f24",n.style.color="#d1d5db",n.style.cursor="pointer",n.addEventListener("click",()=>{r.activeTab=e,P(),N(!0)}),n};l.appendChild(s("signals","Signals")),l.appendChild(s("components","Components")),l.appendChild(s("router","Router")),n.addEventListener("click",()=>{o.style.display="none"===o.style.display?"block":"none","block"===o.style.display&&(P(),N(!0))}),o.appendChild(l),o.appendChild(a),t.appendChild(n),t.appendChild(o),document.body.appendChild(t),r.root=t,r.panel=o,r.content=a}function I(){r.enabled&&(r.enabled=!1,null!=r.refreshId&&(clearInterval(r.refreshId),r.refreshId=null),e(null),t(null),x(),r.root?.parentNode&&r.root.parentNode.removeChild(r.root),r.root=null,r.panel=null,r.content=null,r.dispose=null,r.renderedTab=null,r.renderKeys={signals:"",components:"",router:""},r.scrollMemo={signals:{top:0,left:0},components:{top:0,left:0},router:{top:0,left:0}})}function L(n={}){if(typeof document>"u")return{disable:()=>{}};if(r.enabled&&r.dispose)return{disable:r.dispose};let o=Math.max(100,n.refreshMs??350),a=Math.max(1,n.historyLimit??50),i=n.position??"bottom-right";r.enabled=!0,r.activeTab="signals",e({onCreate(e,t){p(e,t)},onWrite(e,t){let n=p(e,t),o=Date.now();n.lastUpdated=o,n.history.push({at:o,value:t}),n.history.length>a&&n.history.splice(0,n.history.length-a)}}),t({onMountStart(e){let t=s.get(e);t??(t=u++,s.set(e,t));let n=l.length>0?l[l.length-1]:null;c.set(t,{id:t,parentId:n,debugName:h(e),mountedAt:Date.now(),hasDefaultSlot:null!=e.children,slotNames:g(e),props:_(e),ref:f(e)}),l.push(t)},onMountEnd(e){let t=s.get(e);if(null==t)return;let n=c.get(t);if(n&&(n.debugName=h(e),n.hasDefaultSlot=null!=e.children,n.slotNames=g(e),n.props=_(e)),l[l.length-1]===t)return void l.pop();let o=l.lastIndexOf(t);o>=0&&l.splice(o,1)},onUnmount(e){let t=s.get(e);if(null==t)return;b(t);let n=l.lastIndexOf(t);n>=0&&l.splice(n,1)}}),F({position:i}),r.refreshId=setInterval(()=>{"block"===r.panel?.style.display&&N()},o),n.initiallyOpen&&r.panel&&(r.panel.style.display="block",P(),N(!0));let d=()=>I();return r.dispose=d,{disable:d}}export{I as disableDevTools,L as enableDevTools};
|
package/dist/lib/form.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs");function t(e="Required"){return t=>null==t||""===t||Array.isArray(t)&&0===t.length?e:null}function n(e,t){return r=>"string"==typeof r&&r.length<e?t??`Minimum ${e} characters`:null}function r(e,t){return r=>"string"==typeof r&&r.length>e?t??`Maximum ${e} characters`:null}function i(e,t="Invalid format"){return r=>"string"!=typeof r||e.test(r)?null:t}function a(e="Invalid email"){return i(/^[^\s@]+@[^\s@]+\.[^\s@]+$/,e)}function o(e,t){return r=>"number"==typeof r&&r<e?t??`Minimum value is ${e}`:null}function s(e,t){return r=>"number"==typeof r&&r>e?t??`Maximum value is ${e}`:null}function c(e){return e}var l={required:t,minLength:n,maxLength:r,email:a,pattern:i,min:o,max:s};function u(e,t){return{...e,...t}}function d(t,r=[],n="blur",l){let u=e.signal(t),i=e.signal(!1),o=e.signal(!1),a=e.signal(null),s=e.signal(!1),f=e.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs");function t(e="Required"){return t=>null==t||""===t||Array.isArray(t)&&0===t.length?e:null}function n(e,t){return r=>"string"==typeof r&&r.length<e?t??`Minimum ${e} characters`:null}function r(e,t){return r=>"string"==typeof r&&r.length>e?t??`Maximum ${e} characters`:null}function i(e,t="Invalid format"){return r=>"string"!=typeof r||e.test(r)?null:t}function a(e="Invalid email"){return i(/^[^\s@]+@[^\s@]+\.[^\s@]+$/,e)}function o(e,t){return r=>"number"==typeof r&&r<e?t??`Minimum value is ${e}`:null}function s(e,t){return r=>"number"==typeof r&&r>e?t??`Maximum value is ${e}`:null}function c(e){return e}var l={required:t,minLength:n,maxLength:r,email:a,pattern:i,min:o,max:s};function u(e,t){return{...e,...t}}function d(t,r=[],n="blur",l){let u=e.signal(t),i=e.signal(!1),o=e.signal(!1),a=e.signal(null),s=e.signal(!1),f=!0,c=e.effect(()=>{u.value,f?f=!1:null!==a.peek()&&(a.value=null)}),v=e.computed(()=>{if(a.value)return a.value;let e=l?.();for(let t of r){let r=t(u.value,e);if(r)return r}return null}),p=e.computed(()=>("input"===n?o.value||i.value:"submit"===n?s.value:i.value)?v.value:null);return{value:u,error:p,rawError:v,touched:i,dirty:o,onInput:e=>{u.value=function(e){if(!e||!("value"in e))return t;let r=e;return"boolean"==typeof t?r.checked:"number"==typeof t?Number(r.value):r.value}(e.target),o.value=!0},onBlur:()=>{i.value=!0},reset:function(){e.batch(()=>{u.value=t,i.value=!1,o.value=!1,a.value=null,s.value=!1})},_setExternalError:function(e){a.value=e,e&&(i.value=!0)},_forceVisible:function(){i.value=!0,s.value=!0},_dispose:function(){c(),p.dispose(),v.dispose()}}}function f(t,r={},n="blur"){function l(e){let t={};for(let l in e){let u=r[l]??[];t[l]=d(e[l],u,n)}return t}let u=e.signal(t.map(l)),i=e.computed(()=>u.value.length);return{fields:u,append:function(e){u.value=[...u.value,l(e)]},remove:function(e){let t=u.value;if(!(e<0||e>=t.length)){for(let r in t[e])t[e][r]._dispose();u.value=t.filter((t,r)=>r!==e)}},move:function(e,t){let r=[...u.value];if(e<0||e>=r.length||t<0||t>=r.length||e===t)return;let[n]=r.splice(e,1);r.splice(t,0,n),u.value=r},replace:function(e,t){let r=[...u.value];if(!(e<0||e>=r.length)){for(let t in r[e])r[e][t]._dispose();r[e]=l(t),u.value=r}},length:i,reset:function(){for(let e of u.value)for(let t in e)e[t]._dispose();u.value=t.map(l)},_dispose:function(){for(let e of u.value)for(let t in e)e[t]._dispose();i.dispose()}}}function p(e){return"object"==typeof e&&!!e&&!Array.isArray(e)}function m(e,t="",r=[]){for(let[n,l]of Object.entries(e)){let e=t?`${t}.${n}`:n;p(l)&&Object.keys(l).length>0?m(l,e,r):r.push([e,l])}return r}function h(e,t,r){let n=t.split("."),l=e;for(let e=0;e<n.length-1;e++){let t=n[e];p(l[t])||(l[t]={}),l=l[t]}l[n[n.length-1]]=r}function g(t,r={}){let n=r.validateOn??"blur",l={},u=r.validators;function i(){let e={};for(let t in l)h(e,t,l[t].value.value);return e}for(let[e,r]of m(t))l[e]=d(r,u?.[e]??[],n,i);let o=e.signal(!1),a=e.signal(0),s=e.computed(()=>i()),f=e.computed(()=>{let e={};for(let t in l){let r=l[t].error.value;r&&(e[t]=r)}return e}),c=e.computed(()=>{for(let e in l)if(l[e].rawError.value)return!1;return!0}),v=e.computed(()=>{for(let e in l)if(l[e].error.value)return!1;return!0}),p=e.computed(()=>{for(let e in l)if(l[e].dirty.value)return!0;return!1}),g=e.computed(()=>{for(let e in l)if(l[e].touched.value)return!0;return!1});function x(e){for(let t in e)l[t]?._setExternalError(e[t]??null)}return{fields:l,values:s,errors:f,canSubmit:c,valid:v,dirty:p,touched:g,isSubmitting:o,submitCount:a,handleSubmit:function(e){return t=>{t.preventDefault(),a.value++;for(let e in l)l[e]._forceVisible();let n=s.value;if(r.validate){let e=r.validate(n);if(e){let t={},r=!1;for(let n in e){let l=e[n],u=Array.isArray(l)?l[0]??null:l??null;u&&(t[n]=u,r=!0)}if(r)return void x(t)}}for(let e in l)if(l[e].rawError.value)return;let u=e(n);u instanceof Promise&&(o.value=!0,u.finally(()=>{o.value=!1}).catch(()=>{}))}},reset:function(){for(let e in l)l[e].reset();o.value=!1,a.value=0},setErrors:x,dispose:function(){s.dispose(),f.dispose(),c.dispose(),v.dispose(),p.dispose(),g.dispose();for(let e in l)l[e]._dispose()}}}exports.createForm=g,exports.createValidator=c,exports.email=a,exports.extendValidators=u,exports.max=s,exports.maxLength=r,exports.min=o,exports.minLength=n,exports.nixField=d,exports.nixFieldArray=f,exports.pattern=i,exports.required=t,exports.validators=l;
|
package/dist/lib/form.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{batch as e,computed as t,effect as n,signal as r}from"./signals.js";function i(e="Required"){return t=>null==t||""===t||Array.isArray(t)&&0===t.length?e:null}function a(e,t){return r=>"string"==typeof r&&r.length<e?t??`Minimum ${e} characters`:null}function o(e,t){return r=>"string"==typeof r&&r.length>e?t??`Maximum ${e} characters`:null}function s(e,t="Invalid format"){return r=>"string"!=typeof r||e.test(r)?null:t}function c(e="Invalid email"){return s(/^[^\s@]+@[^\s@]+\.[^\s@]+$/,e)}function l(e,t){return r=>"number"==typeof r&&r<e?t??`Minimum value is ${e}`:null}function u(e,t){return r=>"number"==typeof r&&r>e?t??`Maximum value is ${e}`:null}function d(e){return e}var f={required:i,minLength:a,maxLength:o,email:c,pattern:s,min:l,max:u};function p(e,t){return{...e,...t}}function m(l,u=[],i="blur",a){let o=r(l),s=r(!1),f=r(!1),v=r(null),c=r(!1),d=!0,p=n(()=>{o.value,d?d=!1:null!==v.peek()&&(v.value=null)}),m=t(()=>{if(v.value)return v.value;let e=a?.();for(let t of u){let r=t(o.value,e);if(r)return r}return null}),h=t(()=>("input"===i?f.value||s.value:"submit"===i?c.value:s.value)?m.value:null);return{value:o,error:h,rawError:m,touched:s,dirty:f,onInput:e=>{o.value=function(e){if(!e||!("value"in e))return l;let t=e;return"boolean"==typeof l?t.checked:"number"==typeof l?Number(t.value):t.value}(e.target),f.value=!0},onBlur:()=>{s.value=!0},reset:function(){e(()=>{o.value=l,s.value=!1,f.value=!1,v.value=null,c.value=!1})},_setExternalError:function(e){v.value=e,e&&(s.value=!0)},_forceVisible:function(){s.value=!0,c.value=!0},_dispose:function(){p(),h.dispose(),m.dispose()}}}function h(e,n={},l="blur"){function u(e){let t={};for(let r in e){let u=n[r]??[];t[r]=m(e[r],u,l)}return t}let i=r(e.map(u)),a=t(()=>i.value.length);return{fields:i,append:function(e){i.value=[...i.value,u(e)]},remove:function(e){let t=i.value;if(!(e<0||e>=t.length)){for(let r in t[e])t[e][r]._dispose();i.value=t.filter((t,r)=>r!==e)}},move:function(e,t){let r=[...i.value];if(e<0||e>=r.length||t<0||t>=r.length||e===t)return;let[n]=r.splice(e,1);r.splice(t,0,n),i.value=r},replace:function(e,t){let r=[...i.value];if(!(e<0||e>=r.length)){for(let t in r[e])r[e][t]._dispose();r[e]=u(t),i.value=r}},length:a,reset:function(){for(let e of i.value)for(let t in e)e[t]._dispose();i.value=e.map(u)},_dispose:function(){for(let e of i.value)for(let t in e)e[t]._dispose();a.dispose()}}}function g(e){return"object"==typeof e&&!!e&&!Array.isArray(e)}function _(e,t="",r=[]){for(let[n,l]of Object.entries(e)){let e=t?`${t}.${n}`:n;g(l)&&Object.keys(l).length>0?_(l,e,r):r.push([e,l])}return r}function v(e,t,r){let n=t.split("."),l=e;for(let e=0;e<n.length-1;e++){let t=n[e];g(l[t])||(l[t]={}),l=l[t]}l[n[n.length-1]]=r}function y(e,n={}){let l=n.validateOn??"blur",u={},i=n.validators;function a(){let e={};for(let t in u)v(e,t,u[t].value.value);return e}for(let[t,r]of _(e))u[t]=m(r,i?.[t]??[],l,a);let o=r(!1),s=r(0),f=t(()=>a()),c=t(()=>{let e={};for(let t in u){let r=u[t].error.value;r&&(e[t]=r)}return e}),d=t(()=>{for(let e in u)if(u[e].rawError.value)return!1;return!0}),p=t(()=>{for(let e in u)if(u[e].error.value)return!1;return!0}),h=t(()=>{for(let e in u)if(u[e].dirty.value)return!0;return!1}),g=t(()=>{for(let e in u)if(u[e].touched.value)return!0;return!1});function y(e){for(let t in e)u[t]?._setExternalError(e[t]??null)}return{fields:u,values:f,errors:c,canSubmit:d,valid:p,dirty:h,touched:g,isSubmitting:o,submitCount:s,handleSubmit:function(e){return t=>{t.preventDefault(),s.value++;for(let e in u)u[e]._forceVisible();let r=f.value;if(n.validate){let e=n.validate(r);if(e){let t={},r=!1;for(let n in e){let l=e[n],u=Array.isArray(l)?l[0]??null:l??null;u&&(t[n]=u,r=!0)}if(r)return void y(t)}}for(let e in u)if(u[e].rawError.value)return;let l=e(r);l instanceof Promise&&(o.value=!0,l.finally(()=>{o.value=!1}).catch(()=>{}))}},reset:function(){for(let e in u)u[e].reset();o.value=!1,s.value=0},setErrors:y,dispose:function(){f.dispose(),c.dispose(),d.dispose(),p.dispose(),h.dispose(),g.dispose();for(let e in u)u[e]._dispose()}}}export{y as createForm,d as createValidator,c as email,p as extendValidators,u as max,o as maxLength,l as min,a as minLength,m as nixField,h as nixFieldArray,s as pattern,i as required,f as validators};
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Signal, signal, effect, computed, batch, watch, untrack, nextTick, html, repeat, ref, showWhen, portal, createPortalOutlet, portalOutlet, provideOutlet, injectOutlet, createErrorBoundary, transition, mount, NixComponent, createStore, createRouter, RouterView, Link,
|
|
1
|
+
export { Signal, signal, effect, computed, batch, watch, untrack, nextTick, html, repeat, ref, showWhen, portal, createPortalOutlet, portalOutlet, provideOutlet, injectOutlet, createErrorBoundary, transition, mount, NixComponent, createStore, createRouter, RouterView, Link, nixRouter, RouterKey, suspend, lazy, provide, inject, createInjectionKey, nixField, nixFieldArray, createForm, required, minLength, maxLength, email, pattern, min, max, createValidator, validators, extendValidators, } from "./nix";
|
|
2
2
|
export type { WatchOptions, NixTemplate, NixMountHandle, MountOptions, KeyedList, NixRef, PortalOutlet, ErrorFallback, TransitionOptions, TransitionContent, Store, StoreSignals, Router, NamedRouteLocation, RouteLocation, RouteRecord, RouterOptions, NavigationGuard, NavigationGuardResult, AfterEachHook, ResolvedRoute, ScrollPosition, ScrollBehavior, RouterMode, SuspenseOptions, InjectionKey, Validator, ValidateOn, FieldState, FieldArrayState, FieldErrors, FormState, FormOptions, ValidatorsBase, NixChildren, } from "./nix";
|
package/dist/lib/nix/form.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import type { Signal } from "./reactivity";
|
|
2
2
|
/**
|
|
3
|
-
* A validator function. Return an error string, or null/
|
|
3
|
+
* A validator function. Return an error string when invalid, or `null` /
|
|
4
|
+
* `undefined` when valid.
|
|
4
5
|
*
|
|
5
|
-
* `allValues` is
|
|
6
|
+
* `allValues` is provided when the validator runs inside `createForm`, enabling
|
|
7
|
+
* cross-field validation (e.g., "confirm password matches password").
|
|
8
|
+
*
|
|
9
|
+
* **Validators must be pure.** They are invoked reactively whenever the field
|
|
10
|
+
* value changes — potentially many times per keystroke in forms with
|
|
11
|
+
* cross-field rules — and may run inside computed signals that assume
|
|
12
|
+
* deterministic output. Do not perform I/O, mutate external state, or rely on
|
|
13
|
+
* `Date.now()` / `Math.random()` inside a validator. For asynchronous checks
|
|
14
|
+
* (uniqueness, server-side rules), submit the form and inject the result via
|
|
15
|
+
* {@link FormState.setErrors}.
|
|
6
16
|
*/
|
|
7
17
|
export type Validator<T, AllValues = unknown> = (value: T, allValues?: AllValues) => string | null | undefined;
|
|
8
18
|
export declare function required(message?: string): Validator<unknown>;
|
|
@@ -12,7 +22,7 @@ export declare function pattern(regex: RegExp, message?: string): Validator<stri
|
|
|
12
22
|
export declare function email(message?: string): Validator<string>;
|
|
13
23
|
export declare function min(n: number, message?: string): Validator<number>;
|
|
14
24
|
export declare function max(n: number, message?: string): Validator<number>;
|
|
15
|
-
/** Creates a typed custom validator compatible with `
|
|
25
|
+
/** Creates a typed custom validator compatible with `nixField` and `createForm`. */
|
|
16
26
|
export declare function createValidator<T, AllValues = unknown>(fn: (value: T, allValues?: AllValues) => string | null | undefined): Validator<T, AllValues>;
|
|
17
27
|
/** All built-in validators grouped as a namespace. Extensible via `extendValidators`. */
|
|
18
28
|
export declare const validators: {
|
|
@@ -42,11 +52,13 @@ export type ValidateOn = "blur" | "input" | "submit";
|
|
|
42
52
|
export interface FieldState<T> {
|
|
43
53
|
/** Current value — read/write signal. */
|
|
44
54
|
value: Signal<T>;
|
|
55
|
+
/** Error visible según validateOn. Para UI. */
|
|
56
|
+
readonly error: Signal<string | null>;
|
|
45
57
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
58
|
+
* Error real, ignorando validateOn/touched/dirty.
|
|
59
|
+
* Para lógica de habilitación de botones, validez global, etc.
|
|
48
60
|
*/
|
|
49
|
-
readonly
|
|
61
|
+
readonly rawError: Signal<string | null>;
|
|
50
62
|
/** True after the input has lost focus at least once. */
|
|
51
63
|
touched: Signal<boolean>;
|
|
52
64
|
/** True after the user has typed at least once. */
|
|
@@ -68,7 +80,7 @@ export interface FieldState<T> {
|
|
|
68
80
|
_dispose(): void;
|
|
69
81
|
}
|
|
70
82
|
/** Creates a standalone reactive form field with optional validators. */
|
|
71
|
-
export declare function
|
|
83
|
+
export declare function nixField<T, AllValues = unknown>(initialValue: T, fieldValidators?: Validator<T, AllValues>[], validateOn?: ValidateOn, getAllValues?: () => AllValues): FieldState<T>;
|
|
72
84
|
/** Public state of a field array (dynamic list of field groups). */
|
|
73
85
|
export interface FieldArrayState<T extends Record<string, unknown>> {
|
|
74
86
|
/** Reactive list of field group states. */
|
|
@@ -97,13 +109,13 @@ export interface FieldArrayState<T extends Record<string, unknown>> {
|
|
|
97
109
|
* Creates a reactive array of field groups for dynamic list forms.
|
|
98
110
|
*
|
|
99
111
|
* @example
|
|
100
|
-
* const items =
|
|
112
|
+
* const items = nixFieldArray([{ name: "" }], {
|
|
101
113
|
* name: [required()],
|
|
102
114
|
* });
|
|
103
115
|
* items.append({ name: "nuevo" });
|
|
104
116
|
* items.remove(0);
|
|
105
117
|
*/
|
|
106
|
-
export declare function
|
|
118
|
+
export declare function nixFieldArray<T extends Record<string, unknown>>(initialItems: T[], fieldValidators?: {
|
|
107
119
|
[K in keyof T]?: Validator<T[K], unknown>[];
|
|
108
120
|
}, validateOn?: ValidateOn): FieldArrayState<T>;
|
|
109
121
|
/** Field-name map that supports top-level keys and dot-path nested keys. */
|
|
@@ -125,8 +137,43 @@ export interface FormState<T extends Record<string, unknown>> {
|
|
|
125
137
|
readonly values: Signal<T>;
|
|
126
138
|
/** Computed map of all currently visible field errors. */
|
|
127
139
|
readonly errors: Signal<FieldErrors<T>>;
|
|
128
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* True when no field has a *visible* error.
|
|
142
|
+
*
|
|
143
|
+
* Visibility follows `validateOn`, so this signal reflects what the user
|
|
144
|
+
* currently sees in the UI — not the underlying validity of the data.
|
|
145
|
+
* Use it to drive error summaries, banners, or any UI that should only
|
|
146
|
+
* react to errors the user has been shown.
|
|
147
|
+
*
|
|
148
|
+
* For enabling or disabling submit buttons, use {@link canSubmit} instead.
|
|
149
|
+
*/
|
|
129
150
|
readonly valid: Signal<boolean>;
|
|
151
|
+
/**
|
|
152
|
+
* True when every per-field validator passes against the current values,
|
|
153
|
+
* regardless of `touched`, `dirty`, or `validateOn`.
|
|
154
|
+
*
|
|
155
|
+
* This is the signal to bind to submit buttons:
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* <button disabled=${() => !form.canSubmit.value || form.isSubmitting.value}>
|
|
159
|
+
* Save
|
|
160
|
+
* </button>
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* Unlike {@link valid}, `canSubmit` does not depend on whether errors are
|
|
164
|
+
* currently visible — a pristine form with empty required fields starts
|
|
165
|
+
* as `false` and flips to `true` the moment all validators pass.
|
|
166
|
+
*
|
|
167
|
+
* External errors injected via {@link setErrors} also flip `canSubmit` to
|
|
168
|
+
* `false` until the user edits the affected field.
|
|
169
|
+
*
|
|
170
|
+
* **Note:** `canSubmit` does not execute `options.validate` (schema-level
|
|
171
|
+
* validators such as Zod). Schema validation runs only on submit, by design,
|
|
172
|
+
* to keep per-keystroke cost predictable. If you need a schema rule to
|
|
173
|
+
* affect `canSubmit` reactively, express it as a per-field validator in
|
|
174
|
+
* `options.validators` instead.
|
|
175
|
+
*/
|
|
176
|
+
readonly canSubmit: Signal<boolean>;
|
|
130
177
|
/** True when at least one field has been modified. */
|
|
131
178
|
readonly dirty: Signal<boolean>;
|
|
132
179
|
/** True when at least one field has been touched (lost focus). */
|
package/dist/lib/nix/index.d.ts
CHANGED
|
@@ -8,11 +8,11 @@ export { NixComponent } from "./lifecycle";
|
|
|
8
8
|
export type { NixChildren } from "./lifecycle";
|
|
9
9
|
export { createStore } from "./store";
|
|
10
10
|
export type { Store, StoreSignals } from "./store";
|
|
11
|
-
export { createRouter, RouterView, Link,
|
|
11
|
+
export { createRouter, RouterView, Link, nixRouter, RouterKey } from "./router";
|
|
12
12
|
export type { Router, NamedRouteLocation, RouteLocation, RouteRecord, RouterOptions, NavigationGuard, NavigationGuardResult, AfterEachHook, ResolvedRoute, ScrollPosition, ScrollBehavior, RouterMode, } from "./router";
|
|
13
13
|
export { suspend, lazy } from "./async";
|
|
14
14
|
export type { SuspenseOptions } from "./async";
|
|
15
15
|
export { provide, inject, createInjectionKey } from "./context";
|
|
16
16
|
export type { InjectionKey } from "./context";
|
|
17
|
-
export {
|
|
17
|
+
export { nixField, nixFieldArray, createForm, required, minLength, maxLength, email, pattern, min, max, createValidator, validators, extendValidators, } from "./form";
|
|
18
18
|
export type { Validator, ValidateOn, FieldState, FieldArrayState, FieldErrors, FormState, FormOptions, ValidatorsBase } from "./form";
|
package/dist/lib/nix/router.d.ts
CHANGED
|
@@ -144,7 +144,7 @@ export interface _RouterDebugInternal {
|
|
|
144
144
|
*/
|
|
145
145
|
export declare function createRouter(routes: RouteRecord[], options?: RouterOptions): Router;
|
|
146
146
|
/** Returns the active router singleton. */
|
|
147
|
-
export declare function
|
|
147
|
+
export declare function nixRouter(): Router;
|
|
148
148
|
/**
|
|
149
149
|
* @internal — Resets the router singleton. Used by tests to avoid
|
|
150
150
|
* "A router already exists" warnings between test cases.
|
package/dist/lib/nix-js.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs"),t=require("./template2.cjs"),n=require("./lifecycle.cjs"),r=require("./context.cjs"),i=require("./router.cjs"),a=require("./component.cjs"),o=require("./store.cjs"),s=require("./async.cjs"),c=require("./form.cjs");exports.Link=i.Link,exports.NixComponent=n.NixComponent,exports.RouterKey=i.RouterKey,exports.RouterView=i.RouterView,exports.Signal=e.Signal,exports.batch=e.batch,exports.computed=e.computed,exports.createErrorBoundary=t.t,exports.createForm=c.createForm,exports.createInjectionKey=r.createInjectionKey,exports.createPortalOutlet=t.n,exports.createRouter=i.createRouter,exports.createStore=o.createStore,exports.createValidator=c.createValidator,exports.effect=e.effect,exports.email=c.email,exports.extendValidators=c.extendValidators,exports.html=t.l,exports.inject=r.inject,exports.injectOutlet=t.r,exports.lazy=s.lazy,exports.max=c.max,exports.maxLength=c.maxLength,exports.min=c.min,exports.minLength=c.minLength,exports.mount=a.mount,exports.nextTick=e.nextTick,exports.pattern=c.pattern,exports.portal=t.i,exports.portalOutlet=t.a,exports.provide=r.provide,exports.provideOutlet=t.o,exports.ref=t.h,exports.repeat=t.d,exports.required=c.required,exports.showWhen=t.u,exports.signal=e.signal,exports.suspend=s.suspend,exports.transition=t.s,exports.untrack=e.untrack,exports.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./signals.cjs"),t=require("./template2.cjs"),n=require("./lifecycle.cjs"),r=require("./context.cjs"),i=require("./router.cjs"),a=require("./component.cjs"),o=require("./store.cjs"),s=require("./async.cjs"),c=require("./form.cjs");exports.Link=i.Link,exports.NixComponent=n.NixComponent,exports.RouterKey=i.RouterKey,exports.RouterView=i.RouterView,exports.Signal=e.Signal,exports.batch=e.batch,exports.computed=e.computed,exports.createErrorBoundary=t.t,exports.createForm=c.createForm,exports.createInjectionKey=r.createInjectionKey,exports.createPortalOutlet=t.n,exports.createRouter=i.createRouter,exports.createStore=o.createStore,exports.createValidator=c.createValidator,exports.effect=e.effect,exports.email=c.email,exports.extendValidators=c.extendValidators,exports.html=t.l,exports.inject=r.inject,exports.injectOutlet=t.r,exports.lazy=s.lazy,exports.max=c.max,exports.maxLength=c.maxLength,exports.min=c.min,exports.minLength=c.minLength,exports.mount=a.mount,exports.nextTick=e.nextTick,exports.nixField=c.nixField,exports.nixFieldArray=c.nixFieldArray,exports.nixRouter=i.nixRouter,exports.pattern=c.pattern,exports.portal=t.i,exports.portalOutlet=t.a,exports.provide=r.provide,exports.provideOutlet=t.o,exports.ref=t.h,exports.repeat=t.d,exports.required=c.required,exports.showWhen=t.u,exports.signal=e.signal,exports.suspend=s.suspend,exports.transition=t.s,exports.untrack=e.untrack,exports.validators=c.validators,exports.watch=e.watch;
|
package/dist/lib/nix-js.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Signal as e,batch as t,computed as n,effect as r,nextTick as i,signal as a,untrack as o,watch as s}from"./signals.js";import{a as c,d as l,h as u,i as d,l as f,n as p,o as m,r as h,s as g,t as _,u as v}from"./template2.js";import{NixComponent as y}from"./lifecycle.js";import{createInjectionKey as b,inject as x,provide as S}from"./context.js";import{Link as C,RouterKey as w,RouterView as T,createRouter as E,
|
|
1
|
+
import{Signal as e,batch as t,computed as n,effect as r,nextTick as i,signal as a,untrack as o,watch as s}from"./signals.js";import{a as c,d as l,h as u,i as d,l as f,n as p,o as m,r as h,s as g,t as _,u as v}from"./template2.js";import{NixComponent as y}from"./lifecycle.js";import{createInjectionKey as b,inject as x,provide as S}from"./context.js";import{Link as C,RouterKey as w,RouterView as T,createRouter as E,nixRouter as D}from"./router.js";import{mount as O}from"./component.js";import{createStore as k}from"./store.js";import{lazy as A,suspend as j}from"./async.js";import{createForm as M,createValidator as N,email as P,extendValidators as F,max as I,maxLength as L,min as R,minLength as z,nixField as B,nixFieldArray as V,pattern as H,required as U,validators as W}from"./form.js";export{C as Link,y as NixComponent,w as RouterKey,T as RouterView,e as Signal,t as batch,n as computed,_ as createErrorBoundary,M as createForm,b as createInjectionKey,p as createPortalOutlet,E as createRouter,k as createStore,N as createValidator,r as effect,P as email,F as extendValidators,f as html,x as inject,h as injectOutlet,A as lazy,I as max,L as maxLength,R as min,z as minLength,O as mount,i as nextTick,B as nixField,V as nixFieldArray,D as nixRouter,H as pattern,d as portal,c as portalOutlet,S as provide,m as provideOutlet,u as ref,l as repeat,U as required,v as showWhen,a as signal,j as suspend,g as transition,o as untrack,W as validators,s as watch};
|
package/dist/lib/router.cjs
CHANGED
|
@@ -4,4 +4,4 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=requi
|
|
|
4
4
|
href=${"hash"===n._mode?"#"+o:o}
|
|
5
5
|
style=${()=>n.current.value===e?"color:#38bdf8;font-weight:700;text-decoration:none;cursor:pointer;padding:4px 10px;border-radius:4px;background:#0c2a3a":"color:#a3a3a3;text-decoration:none;cursor:pointer;padding:4px 10px;border-radius:4px"}
|
|
6
6
|
@click=${t=>{t.preventDefault(),n.navigate(e)}}
|
|
7
|
-
>${r}</a>`}};exports.Link=D,exports.RouterKey=i,exports.RouterView=E,exports._debugGetRouterInternal=T,exports._resetRouter=w,exports.createRouter=S,exports.
|
|
7
|
+
>${r}</a>`}};exports.Link=D,exports.RouterKey=i,exports.RouterView=E,exports._debugGetRouterInternal=T,exports._resetRouter=w,exports.createRouter=S,exports.nixRouter=C;
|
package/dist/lib/router.js
CHANGED
|
@@ -4,4 +4,4 @@ import{signal as e}from"./signals.js";import{l as t}from"./template2.js";import{
|
|
|
4
4
|
href=${"hash"===n._mode?"#"+a:a}
|
|
5
5
|
style=${()=>n.current.value===e?"color:#38bdf8;font-weight:700;text-decoration:none;cursor:pointer;padding:4px 10px;border-radius:4px;background:#0c2a3a":"color:#a3a3a3;text-decoration:none;cursor:pointer;padding:4px 10px;border-radius:4px"}
|
|
6
6
|
@click=${t=>{t.preventDefault(),n.navigate(e)}}
|
|
7
|
-
>${r}</a>`}};export{O as Link,a as RouterKey,D as RouterView,E as _debugGetRouterInternal,T as _resetRouter,C as createRouter,w as
|
|
7
|
+
>${r}</a>`}};export{O as Link,a as RouterKey,D as RouterView,E as _debugGetRouterInternal,T as _resetRouter,C as createRouter,w as nixRouter};
|
package/package.json
CHANGED