@grainular/forms 2.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +17 -0
  3. package/dist/browser/index.global.js +2 -0
  4. package/dist/browser/index.global.js.map +1 -0
  5. package/dist/browser/index.js +3 -0
  6. package/dist/browser/index.js.map +9 -0
  7. package/dist/cjs/index.cjs +2 -0
  8. package/dist/cjs/index.cjs.map +1 -0
  9. package/dist/cjs/index.js +3 -0
  10. package/dist/cjs/index.js.map +9 -0
  11. package/dist/esm/index.js +2 -0
  12. package/dist/esm/index.js.map +1 -0
  13. package/dist/types/directives/bind.directive.d.ts +2 -0
  14. package/dist/types/index.d.cts +141 -0
  15. package/dist/types/index.d.ts +14 -0
  16. package/dist/types/lib/control-list.d.ts +12 -0
  17. package/dist/types/lib/control.d.ts +26 -0
  18. package/dist/types/lib/derive-schema-errors.d.ts +3 -0
  19. package/dist/types/lib/derive-schema-touched.d.ts +3 -0
  20. package/dist/types/lib/derive-schema-value.d.ts +3 -0
  21. package/dist/types/lib/form-schema.d.ts +8 -0
  22. package/dist/types/lib/form.d.ts +18 -0
  23. package/dist/types/lib/handle-form-value.d.ts +2 -0
  24. package/dist/types/lib/iterate-schema.d.ts +3 -0
  25. package/dist/types/lib/touch-all.d.ts +2 -0
  26. package/dist/types/lib/value-binding.d.ts +6 -0
  27. package/dist/types/structs/control-errors.struct.d.ts +11 -0
  28. package/dist/types/validators/core.d.ts +7 -0
  29. package/dist/types/validators/create-validator.d.ts +8 -0
  30. package/dist/types/validators/email.d.ts +2 -0
  31. package/dist/types/validators/max-length.d.ts +4 -0
  32. package/dist/types/validators/max.d.ts +4 -0
  33. package/dist/types/validators/min-length.d.ts +4 -0
  34. package/dist/types/validators/min.d.ts +4 -0
  35. package/dist/types/validators/pattern.d.ts +4 -0
  36. package/dist/types/validators/required.d.ts +1 -0
  37. package/dist/types/validators/validate-each.d.ts +3 -0
  38. package/package.json +49 -0
package/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 - Present [Sebastian Heinz](https://github.com/iamsebastiandev)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,17 @@
1
+ <!-- @format -->
2
+
3
+ # @grainular/nord
4
+
5
+ To install dependencies:
6
+
7
+ ```bash
8
+ bun install
9
+ ```
10
+
11
+ To run:
12
+
13
+ ```bash
14
+ bun run src/index.ts
15
+ ```
16
+
17
+ This project was created using `bun init` in bun v1.1.18. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
@@ -0,0 +1,2 @@
1
+ var Nord=(function(exports){'use strict';var A=new(typeof MutationObserver<"u"?class extends MutationObserver{pendingMounts=new Set;activeUnmounts=new Map;constructor(){super(()=>{this.processLifecycle();});}processLifecycle(){for(let e of this.pendingMounts){let{node:t,callback:r}=e;if(t.isConnected){let n=r();if(typeof n=="function"){let o=this.activeUnmounts.get(t);o||(o=new Set,this.activeUnmounts.set(t,o)),o.add(n);}this.pendingMounts.delete(e);}}for(let[e,t]of this.activeUnmounts)if(!e.isConnected){for(let r of t)r();this.activeUnmounts.delete(e);}}start(e){this.observe(e,{childList:true,subtree:true});}trackMount(e,t){this.pendingMounts.add({node:e,callback:t});}trackUnmount(e,t){let r=this.activeUnmounts.get(e);r||(r=new Set,this.activeUnmounts.set(e,r)),r.add(t);}}:class{start(){}trackUnmount(){}trackMount(){}disconnect(){}}),I=e=>{for(let t of e)t.remove();};var O=()=>{let e="";return {fragmentId:true,create:t=>{e=`n\xF8-${t.padStart(6,"0")}`;},get:()=>e}};var W=e=>e!==null&&typeof e=="function"&&"subscribe"in e;var y=e=>{let t=O();return {fragmentId:t,resolve:()=>t.get(),render:()=>"",hydrate:r=>{if(r instanceof Element){let n=e(r);n&&A.trackUnmount(r,n);}}}};var F=e=>{let t=document.createElement("template"),r=new Comment;return t.content.append(r),e.hydrate(r),Array.from(t.content.childNodes)},L=(e,t=()=>"")=>{let r=O();return {fragmentId:r,resolve:()=>`<!--${r.get()}-->`,render:()=>t(),hydrate:n=>{if(n instanceof Comment){let o=e(n);o&&A.trackUnmount(n,o);}}}};var M=e=>{let t=new Map,r=n=>{t.set(true,()=>F(n()));let o=e();return i=>{let a=t.get(o),l=o,u=a?.()??[];if(i.before(...u),W(e))return e.subscribe(d=>{d!==l&&(l=d,I(u),u=t.get(d)?.()??[],i.before(...u));})}};return {$then:n=>{let o=()=>e()?n().render():"",i=r(n);return Object.assign(L(i,o),{$else:a=>(t.set(false,()=>F(a())),L(i,()=>e()?n().render():a().render()))})}}};var H=new Map([[e=>e instanceof HTMLInputElement&&e.type==="checkbox",e=>{let t=e;return {get:()=>t.checked,set:r=>{t.checked=!!r;}}}],[e=>e instanceof HTMLInputElement&&e.type==="radio",e=>{let t=e;return {get:()=>t.value,set:r=>{t.checked=r===t.value;}}}],[e=>e instanceof HTMLInputElement&&e.type==="file",e=>{let t=e;return {get:()=>t.files,set:()=>{}}}],[e=>e instanceof HTMLSelectElement&&e.type==="select-multiple",e=>{let t=e;return {get:()=>Array.from(t.selectedOptions,r=>r.value),set:r=>{queueMicrotask(()=>{let n=Array.isArray(r)?r:[r];for(let o of t.options)o.selected=n.includes(o.value);});}}}],[e=>e instanceof HTMLSelectElement,e=>{let t=e;return {get:()=>Array.from(t.selectedOptions,r=>r.value).at(0),set:r=>{queueMicrotask(()=>{for(let n of t.options)n.selected=r===n.value;});}}}],[e=>e instanceof HTMLInputElement&&(e.type==="number"||e.type==="range"),e=>{let t=e;return {get:()=>t.value===""?null:t.valueAsNumber,set:r=>{t.value=String(r??"");}}}],[e=>e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement,e=>{let t=e;return {get:()=>t.value,set:r=>{t.value=String(r??"");}}}]]),T=e=>{for(let[t,r]of H)if(t(e))return r(e);return {get:()=>null,set:()=>{}}};var B=(e,t="input")=>y(r=>{let{get:n,set:o}=T(r);o(e());let i=e.subscribe(l=>o(l)),a=()=>e.set(n());return r.addEventListener(t,a),()=>{r.removeEventListener(t,a),i();}});var m=e=>{let t=()=>e.map(r=>r());return Object.assign(t,{subscribe:r=>{let n=e.map(o=>o.subscribe(()=>{r(t());}));return ()=>{for(let o of n)o();}}})},s=(e,t)=>Object.assign(()=>t(e()),{subscribe(r){return e.subscribe(n=>{r(t(n));})}}),v=e=>Object.assign(()=>e()(),{subscribe:t=>{let r=e().subscribe(t),n=e.subscribe(o=>{r(),r=o.subscribe(t),t(o());});return ()=>{r(),n();}}}),D=(e,t)=>Object.is(e,t),f=(e,t=D)=>{let r=e,n=new Set,o=()=>{for(let a of Array.from(n))a(r);},i=a=>{t(r,a)||(r=a,o());};return Object.assign(()=>r,{set:i,update:a=>i(a(r)),subscribe:a=>(n.add(a),()=>n.delete(a))})},$=e=>Object.assign(()=>e(),{subscribe:e.subscribe});var U=(e,t)=>(t()?e.setAttribute("disabled",""):e.removeAttribute("disabled"),t.subscribe(r=>{r?e.setAttribute("disabled",""):e.removeAttribute("disabled");})),R=(e,t,r,n)=>{let o=i=>{i.type==="focus"&&r(),i.type==="blur"&&(t(),n());};return e.addEventListener("focus",o),e.addEventListener("blur",o),()=>{e.removeEventListener("focus",o),e.removeEventListener("blur",o);}},N=(e,t,r,n)=>{let{get:o,set:i}=T(e);i(t());let a=()=>t.set(o());e.addEventListener(r,a);let l=t.subscribe(u=>{n(),i(u);});return ()=>{e.removeEventListener(r,a),l();}},z=({updateOn:e},t,r,n,o,i,a)=>y(l=>{let u=U(l,i),d=R(l,t,r,o),p=N(l,a,e,n);return ()=>{u(),d(),p();}}),E=e=>{let t=f(e),r=f([]),n=f(false),o=s(r,p=>p.length===0),i=f(false),a=f(false),l=f(false),u=()=>{r.set([]),i.set(false),a.set(false),l.set(false),t.set(e);},d=p=>z(p,()=>i.set(true),()=>a.set(true),()=>l.set(true),()=>a.set(false),n,t);return {id:crypto.randomUUID(),isControl:true,value:t,errors:r,disabled:n,isValid:o,touched:i,focused:a,dirty:l,reset:u,bind:(p={})=>d({updateOn:"input",...p})}};var C=e=>"isControl"in e?s(e.errors,t=>t):"isControlList"in e?v(s(e.controls,t=>{let r=t.map(n=>C(n));return s(m(r),n=>n.flat())})):s(m(Object.values(e).map(t=>C(t))),t=>t.flat());var S=e=>"isControl"in e?s(e.touched,t=>[t]):"isControlList"in e?v(s(e.controls,t=>t.map(r=>S(r)))):s(m(Object.values(e).map(t=>S(t))),t=>t.flat());var x=e=>{if("isControl"in e)return $(e.value);if("isControlList"in e)return v(s(e.controls,r=>m(r.map(x))));let t=Object.entries(e).map(([r,n])=>({key:r,grain:x(n)}));return s(m(t.map(r=>r.grain)),r=>r.reduce((n,o,i)=>{let a=t[i].key;return n[a]=o,n},{}))};var k=e=>{let t=e.map(n=>g(n)),r=f(t);return {isControlList:true,controls:r,add:n=>{let o=g(n);r.update(i=>[...i,o]);},remove:n=>{r.update(o=>[...o.filter(i=>i!==n)]);},at:n=>r()[n],set:n=>{let o=n.map(i=>g(i));r.set(o);},reset:()=>{r.set(t);}}};var g=e=>{if(Array.isArray(e))return k(e);if(e!==null&&typeof e=="object"&&!(e instanceof Date)){let t=Object.entries(e).map(([r,n])=>[r,g(n)]);return Object.fromEntries(t)}return E(e)};var V=(e,t)=>{if("isControl"in e&&e.value.set(t),"isControlList"in e&&Array.isArray(t)&&e.set(t),typeof t=="object"&&t!==null)for(let[r,n]of Object.entries(t))r in e&&V(e[r],n);};var h=(e,t)=>{if("isControl"in e)return t(e);if("isControlList"in e){for(let r of e.controls())h(r,t);return}for(let r of Object.values(e))h(r,t);};var w=e=>{h(e,t=>t.touched.set(true));};var P=(e,t=()=>{})=>{let r=g(e),n=x(r),o=C(r),i=s(o,b=>b.length===0),a=S(r),l=s(a,b=>b.some(Boolean)),u=b=>V(r,b),d=()=>h(r,b=>b.reset()),p=()=>(w(r),t(r),o().length===0);return t(r),m([n,a]).subscribe(()=>t(r)),{controls:r,value:n,errors:o,isValid:i,isTouched:l,set:u,reset:d,validate:p}};var q=(e,t,r={showOn:"touched"})=>{let n=s(m([e.errors,e.touched]),([o,i])=>!o||o.length===0?null:r.showOn==="always"||i?o:null);return M(s(n,o=>(o??[]).length>0)).$then(()=>t(s(n,o=>(o??[]).join(", "))))};var G=(e,t)=>{e.errors.update(r=>[...new Set([...r??[],t])]);},j=(e,t)=>{e.errors.update(r=>[...new Set([...(r??[]).filter(n=>n!==t)])]);};var c=e=>(t,{message:r,...n})=>{let o=t,i=()=>G(o,r),a=()=>j(o,r);t.touched()&&e(o,i,a,n);};var Z=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,K=c((e,t,r)=>{let n=e.value();if(n===null||n==="")return r();Z.test(n)?r():t();});var _=c((e,t,r,{max:n})=>{let o=e.value();if(o===null||typeof o!="number")return r();o<=n?r():t();});var X=c((e,t,r,{max:n})=>{let o=e.value();if(!Array.isArray(o)||Array.isArray(o)&&o.length<=n)return r();o.length>n&&t();});var J=c((e,t,r,{min:n})=>{let o=e.value();if(o===null||typeof o!="number")return r();o>=n?r():t();});var Q=c((e,t,r,{min:n})=>{let o=e.value();if(!Array.isArray(o)||Array.isArray(o)&&o.length>=n)return r();o.length<n&&t();});var Y=c((e,t,r,{regex:n})=>{let o=e.value();if(o===null||o==="")return r();n.test(o)?r():t();});var ee=c((e,t,r)=>{let n=e.value();if(typeof n!="string")return n?r():t();n.trim()!==""?r():t();});var te=(e,t)=>{e.controls().forEach((r,n)=>t(r,n));};exports.$controlErrors=q;exports.bind=B;exports.control=E;exports.createValidator=c;exports.email=K;exports.form=P;exports.max=_;exports.maxLength=X;exports.min=J;exports.minLength=Q;exports.pattern=Y;exports.required=ee;exports.touchAll=w;exports.validateEach=te;return exports;})({});//# sourceMappingURL=index.global.js.map
2
+ //# sourceMappingURL=index.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../nord/src/application/lifecycle-observer.ts","../../../nord/src/internals/identifier.ts","../../../nord/src/internals/is-subscribable-value.ts","../../../nord/src/directives/create-directive.ts","../../../nord/src/internals/hydrate-fragment.ts","../../../nord/src/structs/create-struct.ts","../../../nord/src/structs/each.struct.ts","../../../nord/src/structs/if.struct.ts","../../src/lib/value-binding.ts","../../src/directives/bind.directive.ts","../../../grains/src/combined.ts","../../../grains/src/derived.ts","../../../grains/src/flattened.ts","../../../grains/src/grain.ts","../../../grains/src/readonly.ts","../../src/lib/control.ts","../../src/lib/derive-schema-errors.ts","../../src/lib/derive-schema-touched.ts","../../src/lib/derive-schema-value.ts","../../src/lib/control-list.ts","../../src/lib/form-schema.ts","../../src/lib/handle-form-value.ts","../../src/lib/iterate-schema.ts","../../src/lib/touch-all.ts","../../src/lib/form.ts","../../src/structs/control-errors.struct.ts","../../src/validators/core.ts","../../src/validators/create-validator.ts","../../src/validators/email.ts","../../src/validators/max.ts","../../src/validators/max-length.ts","../../src/validators/min.ts","../../src/validators/min-length.ts","../../src/validators/pattern.ts","../../src/validators/required.ts","../../src/validators/validate-each.ts"],"names":["lifecycleObserver","entry","node","callback","cleanup","unmounts","callbacks","fn","disconnectNodes","nodes","createIdentifier","_id","idx","isSubscribableValue","value","createDirective","handler","fragmentId","onDestroy","hydrateFragment","fragment","template","anchor","createStruct","struct","snapshot","$if","conditional","fulfilled","initial","root","currentNodes","previousValue","evaluated","structFn","show","bindings","input","val","select","opt","values","option","getBinding","predicate","factory","bind","event","h","get","set","combined","source","s","subscriber","unsubscribes","derived","run","flattened","nested","innerUnsubscribe","outerUnsubscribe","newInnerGrain","defaultCompareFn","current","next","grain","start","compareFunc","_value","consumers","notifyConsumers","consumer","newValue","updater","readonly","handleNodeDisabledState","disabled","state","handleNodeFocusState","setTouched","setFocused","blur","handleNodeValueBinding","setDirty","createControlBinding","resolveDisabledState","resolveFocusState","resolveValueBinding","control","initialValue","V","errors","isValid","u","touched","focused","dirty","reset","binding","options","deriveSchemaErrors","schema","b","schemas","errorGrains","a","subSchema","deriveSchemaTouched","deriveSchemaValue","p","keyedValues","key","acc","index","controlList","initialValues","initialSchemas","v","createFormSchema","controls","c","updatedSchema","groupEntries","setFormValue","model","iterateSchema","touchAll","form","touchStates","isTouched","states","validate","$controlErrors","renderer","visibleErrors","re","setControlError","message","clearControlError","msg","createValidator","validatorFn","opts","castControl","setError","clearError","EMAIL_REGEX","email","max","maxLength","min","minLength","pattern","regex","required","validateEach","schemaFn"],"mappings":"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","file":"index.global.js","sourcesContent":["export const lifecycleObserver = new (\n typeof MutationObserver !== 'undefined'\n ? class LifecycleObserver extends MutationObserver {\n // We add all callbacks to the mounting queue, and\n // on trigger check if any of the nodes are connected.\n // if yes, the callbacks get executed and the return\n // added to the unmounts\n pendingMounts = new Set<{ node: Node; callback: () => void | (() => void) }>();\n\n // On trigger, we check all nodes in the map if they are\n // still mounted, and if not, run the unmount callback\n activeUnmounts = new Map<Node, Set<() => void>>();\n\n constructor() {\n // We abuse the mutation observer as basically\n // a signal, triggering our lifecycle logic iteration\n super(() => {\n this.processLifecycle();\n });\n }\n\n processLifecycle() {\n for (const entry of this.pendingMounts) {\n const { node, callback } = entry;\n\n // When connected, we run the callback, remove the\n // entry, and add any eventual cleanup to the\n // unmounts map\n if (node.isConnected) {\n const cleanup = callback();\n\n // If it returned a cleanup, register it\n if (typeof cleanup === 'function') {\n let unmounts = this.activeUnmounts.get(node);\n if (!unmounts) {\n unmounts = new Set();\n this.activeUnmounts.set(node, unmounts);\n }\n unmounts.add(cleanup);\n }\n\n // Remove from pending list (Job Done)\n this.pendingMounts.delete(entry);\n }\n }\n\n // Same for the unmounting entries, we iterate them\n // and execute every unmounting cb where the node is disconnected\n for (const [node, callbacks] of this.activeUnmounts) {\n if (!node.isConnected) {\n for (const fn of callbacks) fn();\n this.activeUnmounts.delete(node);\n }\n }\n }\n\n start(node: Node) {\n this.observe(node, { childList: true, subtree: true });\n }\n\n trackMount(node: Node, callback: () => void | (() => void)) {\n this.pendingMounts.add({ node, callback });\n }\n\n trackUnmount(node: Node, callback: () => void) {\n let unmounts = this.activeUnmounts.get(node);\n if (!unmounts) {\n unmounts = new Set();\n this.activeUnmounts.set(node, unmounts);\n }\n unmounts.add(callback);\n }\n }\n : class {\n start() {}\n trackUnmount() {}\n trackMount() {}\n disconnect() {}\n }\n)();\n\nexport const disconnectNodes = (nodes: Element[]) => {\n for (const node of nodes) node.remove();\n};\n","// A regex used to split attribute strings by the\n// current id format.\nexport const identifierRegex = /<!--(nø-.{6})-->/g;\n\nexport const createIdentifier = () => {\n let _id = '';\n\n return {\n fragmentId: true,\n create: (idx: string) => {\n _id = `nø-${idx.padStart(6, '0')}`;\n },\n get: () => _id,\n };\n};\n","import type { Subscribable } from '../application/subscribable';\n\nexport const isSubscribableValue = (value: unknown): value is Subscribable => {\n return value !== null && typeof value === 'function' && 'subscribe' in value;\n};\n","import { lifecycleObserver } from '../application/lifecycle-observer';\nimport { type Fragment } from '../internals/fragment';\nimport { createIdentifier } from '../internals/identifier';\n\n/**\n * A `createDirective` wraps a handler function into a `Fragment` that can be\n * attached to any element in a template. The handler runs when the element is\n * hydrated and receives the element as its argument.\n *\n * ```ts\n * const color = (color: string) =>\n * createDirective((node) => {\n * node.style.backgroundColor = color;\n * });\n *\n * html`<div ${color('red')}>I'm a red div</div>`;\n * ```\n *\n * If the handler returns a function, it is registered as a cleanup callback\n * and called when the element is removed from the DOM.\n */\n\n/**\n * Creates a directive that runs a handler when the target element is hydrated.\n *\n * @param {(node: Element) => void | (() => void)} handler - A function called\n * with the target element on hydration. May return a cleanup function that runs\n * when the element is removed from the DOM.\n *\n * @returns {Fragment} A fragment representing the directive, attachable to\n * elements in a template.\n *\n * @example\n * ```ts\n * const autofocus = createDirective((node) => {\n * node.focus();\n * });\n *\n * html`<input ${autofocus} type=\"text\" />`;\n * ```\n */\nexport const createDirective = (handler: (node: Element) => void | (() => void)): Fragment => {\n const fragmentId = createIdentifier();\n return {\n fragmentId: fragmentId,\n resolve: () => fragmentId.get(),\n render: () => '',\n hydrate: (node: Node) => {\n if (node instanceof Element) {\n const onDestroy = handler(node);\n if (onDestroy) lifecycleObserver.trackUnmount(node, onDestroy);\n }\n },\n } satisfies Fragment;\n};\n","import type { ComponentFragment } from '../component/component-fragment';\n\n/**\n * Method to hydrate a fragment and retrieve it's\n * nodes.\n *\n * @param fragment\n */\nexport const hydrateFragment = (fragment: ComponentFragment) => {\n const template = document.createElement('template');\n const anchor = new Comment();\n\n template.content.append(anchor);\n fragment.hydrate(anchor);\n\n return Array.from(template.content.childNodes) as Element[];\n};\n","import { lifecycleObserver } from '../application/lifecycle-observer';\nimport { type Fragment } from '../internals/fragment';\nimport { createIdentifier } from '../internals/identifier';\n/**\n * `createStruct` is the lower-level counterpart to `createDirective` — where\n * directives target `Element` nodes, structs target `Comment` nodes and are\n * used to manage dynamic regions of the DOM such as conditional blocks,\n * lists, and async content.\n *\n * A struct resolves to an HTML comment anchor in the template, which is then\n * used as a positional reference for inserting and removing nodes at runtime.\n *\n * ```ts\n * const myStruct = createStruct((anchor) => {\n * const node = document.createElement('p');\n * node.textContent = 'Hello';\n * anchor.before(node);\n *\n * return () => node.remove();\n * });\n *\n * html`${myStruct}`;\n * ```\n *\n * If the handler returns a function, it is registered as a cleanup callback\n * and called when the anchor is removed from the DOM.\n */\n\n/**\n * Creates a struct fragment that manages a dynamic DOM region via a comment anchor.\n *\n * @param {(node: Comment) => void | (() => void)} struct - A function called\n * with the comment anchor on hydration. May return a cleanup function that runs\n * when the anchor is removed from the DOM.\n * @param {() => string} [snapshot] - An optional function returning an HTML\n * string for SSR snapshots. Defaults to an empty string.\n *\n * @returns {Fragment} A fragment that resolves to a comment anchor in the\n * template and hydrates the struct when mounted.\n *\n * @example\n * ```ts\n * const myStruct = createStruct(\n * (anchor) => {\n * const node = document.createElement('p');\n * node.textContent = 'Hello';\n * anchor.before(node);\n * return () => node.remove();\n * },\n * () => '<p>Hello</p>',\n * );\n * ```\n */\nexport const createStruct = (\n struct: (node: Comment) => void | (() => void),\n snapshot: () => string = () => '',\n): Fragment => {\n const fragmentId = createIdentifier();\n return {\n fragmentId: fragmentId,\n resolve: () => `<!--${fragmentId.get()}-->`,\n render: () => snapshot(),\n hydrate: (node: Node) => {\n if (node instanceof Comment) {\n const onDestroy = struct(node);\n if (onDestroy) lifecycleObserver.trackUnmount(node, onDestroy);\n }\n },\n };\n};\n","import type { Subscribable } from '../application/subscribable';\nimport type { ComponentFragment } from '../component/component-fragment';\nimport type { Fragment } from '../internals/fragment';\nimport { hydrateFragment } from '../internals/hydrate-fragment';\nimport { isSubscribableValue } from '../internals/is-subscribable-value';\nimport { createStruct } from './create-struct';\n\n/**\n * `$each` is a struct for rendering a list of items into the DOM. It accepts\n * either a plain getter function or a `Subscribable` array and re-renders\n * efficiently when the list changes using keyed reconciliation.\n *\n * ```ts\n * const items = grain([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);\n *\n * html`${$each(items)\n * .$withKey(item => item.id)\n * .$as(item => html`<p>${item.name}</p>`)\n * }`;\n * ```\n *\n * Use `$withKey` to provide a key function for stable identity across updates.\n * Without it, `$as` is used directly and items are keyed by value identity.\n *\n * If the source is a `Subscribable`, the list is kept in sync automatically.\n * Reconciliation uses a longest-increasing-subsequence algorithm to minimise\n * DOM moves when the list changes.\n */\n\ntype KeyFn<T> = (entry: T) => unknown;\ntype RenderFn<T> = (entry: T, idx: number, arr: T[]) => ComponentFragment;\n\ntype EachStruct<T> = {\n /**\n * Renders each item using the provided template function, keyed by value\n * identity. Safe for lists of unique, stable object references. Avoid for\n * primitives or lists that may contain duplicate values — use `$withKey`\n * instead.\n */\n $as: (render: RenderFn<T>) => Fragment;\n\n /**\n * Provides a key function for stable item identity across reconciliation.\n * Recommended whenever items are primitives, may appear more than once,\n * or have unstable object references across updates.\n *\n * @param {KeyFn<T>} keyFn - A function that returns a unique key for each item.\n */\n $withKey: (keyFn: KeyFn<T>) => {\n /**\n * Renders each item using the provided template function, keyed by\n * the value returned from `$withKey`. This is the safest way to render\n * any list and should be preferred in most cases.\n */\n $as: (render: RenderFn<T>) => Fragment;\n };\n};\n\n/**\n * Creates a struct that renders and reconciles a list of items.\n *\n * @template T - The type of each item in the list.\n *\n * @param {(() => T[]) | Subscribable<T[]>} source - A getter function or\n * subscribable that returns the current list of items.\n *\n * @returns {EachStruct<T>} An object with `$as` and `$withKey` methods for\n * specifying how items are keyed and rendered. See each method for guidance\n * on when to use which.\n *\n * @example\n * ```ts\n * // With key — recommended for most cases\n * const users = grain([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]);\n *\n * html`${$each(users)\n * .$withKey(user => user.id)\n * .$as((user) => html`<li>${user.name}</li>`)\n * }`;\n * ```\n *\n * @example\n * ```ts\n * // Without key — only safe for lists of unique, stable object references\n * const items = grain([{ name: 'Alice' }, { name: 'Bob' }]);\n *\n * html`${$each(items)\n * .$as((item) => html`<li>${item.name}</li>`)\n * }`;\n * ```\n */\nexport const $each = <T>(source: (() => T[]) | Subscribable<T[]>): EachStruct<T> => {\n const createEach = (keyFn: (value: T) => unknown, render: RenderFn<T>) =>\n createStruct(\n (anchor) => {\n const cache = new Map<unknown, { nodes: Node[] }>();\n let prevKeys: unknown[] = [];\n\n const create = (item: T, idx: number, arr: T[]) => ({\n nodes: hydrateFragment(render(item, idx, arr)),\n });\n\n const insert = (nodes: Node[], cursor: Node) => {\n const parent = cursor.parentNode;\n const fragment = document.createDocumentFragment();\n fragment.append(...nodes);\n parent?.insertBefore(fragment, cursor);\n };\n\n const removeNodes = (nodes: Node[]) => {\n for (const node of nodes) {\n node.parentNode?.removeChild(node);\n }\n };\n\n const reconcile = (items: T[]) => {\n const keys = items.map(keyFn);\n const keyIndex = new Map<unknown, number>();\n\n for (let i = 0; i < prevKeys.length; i++) {\n keyIndex.set(prevKeys[i], i);\n }\n\n const sources = new Int32Array(keys.length).fill(-1);\n\n for (let i = 0; i < keys.length; i++) {\n const idx = keyIndex.get(keys[i]);\n sources[i] = idx !== undefined ? idx : -1;\n }\n\n const newKeySet = new Set(keys);\n for (const key of prevKeys) {\n if (!newKeySet.has(key)) {\n const entry = cache.get(key);\n\n if (entry) {\n removeNodes(entry.nodes);\n }\n\n cache.delete(key);\n }\n }\n\n const seq = getLIS(sources);\n let j = seq.length - 1;\n let cursor: Node = anchor;\n\n for (let i = keys.length - 1; i >= 0; i--) {\n const key = keys[i];\n let entry = cache.get(key);\n\n if (sources[i] === -1) {\n entry = create(items[i], i, items);\n cache.set(key, entry);\n insert(entry.nodes, cursor);\n } else if (j < 0 || i !== seq[j]) {\n if (entry) {\n insert(entry.nodes, cursor);\n }\n } else {\n j--;\n }\n\n if (entry) {\n cursor = entry.nodes[0];\n }\n }\n\n prevKeys = keys;\n };\n\n reconcile(source());\n\n if (isSubscribableValue(source)) {\n const unsubscribe = source.subscribe(reconcile);\n return () => {\n unsubscribe?.();\n cache.forEach(({ nodes }) => {\n removeNodes(nodes);\n });\n };\n }\n },\n () =>\n source()\n .map((value, idx, arr) => render(value, idx, arr).render())\n .join(''),\n );\n\n return {\n $as: (render: RenderFn<T>) => createEach((value) => value, render),\n $withKey: (keyFn: KeyFn<T>) => ({\n $as: (render: RenderFn<T>) => createEach(keyFn, render),\n }),\n };\n};\n\n/**\n * Computes the longest increasing subsequence (LIS) of the given source\n * indices. Used during reconciliation to determine the minimal set of DOM\n * moves required to update the list.\n *\n * Indices of `-1` denote new items with no previous position and are skipped.\n *\n * @param {Int32Array} sourceIndices - An array mapping each new item's\n * position to its previous position, or `-1` if it is newly inserted.\n *\n * @returns {number[]} The values at the LIS positions in `sourceIndices`.\n */\nfunction getLIS(sourceIndices: Int32Array): number[] {\n const predecessors = new Int32Array(sourceIndices.length);\n const tails: number[] = [];\n\n predecessors.fill(-1);\n\n for (let i = 0; i < sourceIndices.length; i++) {\n const value = sourceIndices[i];\n\n // New items are not part of the stable subsequence\n if (value === -1) continue;\n\n let low = 0;\n let high = tails.length;\n\n while (low < high) {\n const mid = (low + high) >> 1;\n\n if (sourceIndices[tails[mid]] < value) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n\n if (low > 0) {\n predecessors[i] = tails[low - 1];\n }\n\n tails[low] = i;\n }\n\n if (tails.length === 0) return [];\n\n const result = new Array<number>(tails.length);\n let current = tails[tails.length - 1];\n\n for (let i = tails.length - 1; i >= 0; i--) {\n result[i] = current;\n current = predecessors[current];\n }\n\n return result;\n}\n","import { disconnectNodes } from '../application/lifecycle-observer';\nimport type { Subscribable } from '../application/subscribable';\nimport type { ComponentFragment } from '../component/component-fragment';\nimport type { Fragment } from '../internals/fragment';\nimport { hydrateFragment } from '../internals/hydrate-fragment';\nimport { isSubscribableValue } from '../internals/is-subscribable-value';\nimport { createStruct } from './create-struct';\n\n/**\n * `$if` is a struct for conditionally rendering content based on a boolean\n * value or `Subscribable<boolean>`. When the condition changes, the current\n * nodes are disconnected and replaced with the appropriate template.\n *\n * ```ts\n * const isLoggedIn = grain(false);\n *\n * html`${$if(isLoggedIn)\n * .$then(() => html`<p>Welcome back</p>`)\n * .$else(() => html`<p>Please log in</p>`)\n * }`;\n * ```\n *\n * If the source is a plain getter rather than a `Subscribable`, the condition\n * is evaluated once on hydration and never updated.\n */\n\ntype IfThenStruct = {\n /**\n * Specifies the template to render when the condition is `false`.\n * If omitted, nothing is rendered for the false state.\n *\n * @param {() => ComponentFragment} show - A function returning the\n * template to render when the condition is false.\n *\n * @returns {Fragment} A struct fragment that renders either the `$then`\n * or `$else` template depending on the current condition.\n */\n $else: (show: () => ComponentFragment) => Fragment;\n};\n\ntype IfStruct = {\n /**\n * Specifies the template to render when the condition is `true`.\n * Can be chained with `.$else` to specify a fallback for the false state.\n *\n * @param {() => ComponentFragment} fulfilled - A function returning the\n * template to render when the condition is true.\n *\n * @returns {IfThenStruct & Fragment} A struct fragment, chainable with `.$else`.\n */\n $then: (fulfilled: () => ComponentFragment) => IfThenStruct & Fragment;\n};\n\n/**\n * Creates a struct that conditionally renders a template based on a boolean condition.\n *\n * @param {Subscribable<boolean> | (() => boolean)} conditional - A subscribable\n * or getter that provides the boolean condition. If subscribable, the rendered\n * content updates reactively whenever the value changes.\n *\n * @returns {IfStruct} An object with a `$then` method to specify the template\n * to render when the condition is true. Can be chained with `.$else` to specify\n * a fallback for the false state.\n *\n * @example\n * ```ts\n * // Reactive condition with else branch\n * const isLoggedIn = grain(false);\n *\n * html`${$if(isLoggedIn)\n * .$then(() => html`<p>Welcome back</p>`)\n * .$else(() => html`<p>Please log in</p>`)\n * }`;\n * ```\n *\n * @example\n * ```ts\n * // Without else — renders nothing when false\n * const isAdmin = grain(false);\n *\n * html`${$if(isAdmin).$then(() => html`<button>Delete</button>`)}`;\n * ```\n */\nexport const $if = (conditional: Subscribable<boolean> | (() => boolean)): IfStruct => {\n const nodes = new Map<boolean, () => Element[]>();\n\n const struct = (fulfilled: () => ComponentFragment) => {\n nodes.set(true, () => hydrateFragment(fulfilled()));\n const initial = conditional();\n\n return (root: Comment) => {\n const currentNodes = nodes.get(initial);\n let previousValue = initial;\n let evaluated = currentNodes?.() ?? [];\n root.before(...evaluated);\n\n if (isSubscribableValue(conditional)) {\n return conditional.subscribe((value) => {\n // If no changes, do not recreate\n if (value === previousValue) return;\n previousValue = value;\n\n disconnectNodes(evaluated);\n evaluated = nodes.get(value)?.() ?? [];\n root.before(...evaluated);\n });\n }\n };\n };\n\n return {\n $then: (fulfilled: () => ComponentFragment) => {\n const snapshot = () => (conditional() ? fulfilled().render() : '');\n const structFn = struct(fulfilled);\n\n return Object.assign(createStruct(structFn, snapshot), {\n $else: (show: () => ComponentFragment) => {\n nodes.set(false, () => hydrateFragment(show()));\n return createStruct(structFn, () => (!conditional() ? show().render() : fulfilled().render()));\n },\n });\n },\n };\n};\n","// --- Interfaces ---\ntype Binding = {\n get: () => unknown;\n set: (value: unknown) => void;\n};\n\ntype Predicate = (node: Element) => boolean;\ntype Factory = (node: Element) => Binding;\n\n// --- The Dictionary ---\nconst bindings = new Map<Predicate, Factory>([\n // 1. Checkbox\n [\n (node) => node instanceof HTMLInputElement && node.type === 'checkbox',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.checked,\n set: (val) => {\n input.checked = Boolean(val);\n },\n };\n },\n ],\n // 1.5 -> Radio\n [\n (node) => node instanceof HTMLInputElement && node.type === 'radio',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.value,\n set: (val) => {\n input.checked = val === input.value;\n },\n };\n },\n ],\n // 2. File Input (Read-Only)\n [\n (node) => node instanceof HTMLInputElement && node.type === 'file',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.files,\n set: () => {\n /* No-op: File inputs are security locked */\n },\n };\n },\n ],\n // 3. Multi-Select\n [\n (node) => node instanceof HTMLSelectElement && node.type === 'select-multiple',\n (node) => {\n const select = node as HTMLSelectElement;\n return {\n get: () => Array.from(select.selectedOptions, (opt) => opt.value),\n set: (val) => {\n queueMicrotask(() => {\n const values = Array.isArray(val) ? val : [val];\n for (const option of select.options) {\n option.selected = values.includes(option.value);\n }\n });\n },\n };\n },\n ],\n // 3.5 -> Single Select\n [\n (node) => node instanceof HTMLSelectElement,\n (node) => {\n const select = node as HTMLSelectElement;\n return {\n get: () => Array.from(select.selectedOptions, (opt) => opt.value).at(0),\n set: (val) => {\n queueMicrotask(() => {\n for (const option of select.options) {\n option.selected = val === option.value;\n }\n });\n },\n };\n },\n ],\n // 4. Numeric Inputs (Number & Range)\n [\n (node) => node instanceof HTMLInputElement && (node.type === 'number' || node.type === 'range'),\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => (input.value === '' ? null : input.valueAsNumber),\n set: (val) => {\n input.value = String(val ?? '');\n },\n };\n },\n ],\n // 5. Default Fallback (Text, Textarea, Single Select, etc.)\n [\n (node) => node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement,\n (node) => {\n // Safe to cast to generic input interface usually, or just use 'value' property\n const input = node as HTMLInputElement;\n return {\n get: () => input.value,\n set: (val) => {\n input.value = String(val ?? '');\n },\n };\n },\n ],\n]);\n\nexport const getBinding = (node: Element): Binding => {\n for (const [predicate, factory] of bindings) {\n if (predicate(node)) return factory(node);\n }\n // Fallback for non-form elements (or throw error)\n return { get: () => null, set: () => {} };\n};\n","import type { WritableGrain } from '@grainular/grains';\nimport { createDirective } from '@grainular/nord';\nimport { getBinding } from '../lib/value-binding';\n\nexport const bind = <V>(value: WritableGrain<V>, event: 'change' | 'input' | 'blur' = 'input') => {\n return createDirective((node) => {\n const { get, set } = getBinding(node);\n\n // Setter logic\n set(value());\n const cleanup = value.subscribe((value) => set(value));\n\n // Handler logic\n const handler = () => value.set(get() as V);\n node.addEventListener(event, handler);\n\n return () => {\n node.removeEventListener(event, handler);\n cleanup();\n };\n });\n};\n","/** @format */\n\nimport type { Grain, Subscriber } from './grain';\n\n/**\n * A `combined` grain derives its value from an array of source grains,\n * mapping each source to its current value. The result is a tuple typed\n * to match the exact shape of the source array.\n *\n * Like all grains, the value is read by calling it:\n *\n * ```ts\n * const a = grain(1);\n * const b = grain('hello');\n * const ab = combined([a, b]);\n * const value = ab(); // [1, 'hello']\n * ```\n *\n * Reads are always synchronous and never stale — the value is derived\n * on the fly from the current state of each source grain.\n *\n * Subscribers are notified whenever any source grain changes.\n * All source subscriptions are cleaned up when the returned unsubscribe\n * function is called.\n */\n\n// INTERNAL USE ONLY\ntype GrainValue<T extends readonly Grain[]> = {\n [K in keyof T]: T[K] extends Grain<infer U> ? U : never;\n};\n\ntype CombinedFn = {\n <Source extends [Grain, ...Grain[]]>(source: Source): Grain<GrainValue<Source>>;\n <Source extends Grain[]>(source: Source): Grain<GrainValue<Source>>;\n <Source extends readonly Grain[]>(source: Source): Grain<GrainValue<Source>>;\n};\n\n/**\n * Combines an array of grains into a single readonly grain whose value\n * is a tuple of each source grain's current value.\n *\n * @template Source - The tuple or array of source grains.\n *\n * @param {Source} source - The grains to combine.\n *\n * @returns {Grain<GrainValue<Source>>} A readonly grain containing a tuple\n * of the current values of all source grains. Subscribers are notified\n * whenever any source grain's value changes.\n *\n * @example\n * ```ts\n * // Combining grains and subscribing to changes\n * const count = grain(0);\n * const label = grain('hello');\n * const both = combined([count, label]);\n *\n * both.subscribe(([count, label]) => console.log(count, label));\n * count.set(1); // Logs: 1 'hello'\n * label.set('world'); // Logs: 1 'world'\n * ```\n */\nexport const combined: CombinedFn = <Source extends [Grain, ...Grain[]]>(source: Source) => {\n const value = () => source.map((s) => s()) as GrainValue<Source>;\n\n return Object.assign(value, {\n subscribe: (subscriber: Subscriber<GrainValue<Source>>) => {\n // tracking the source subscriptions to make sure that\n // we can clean up any subscription once the grain is\n // cleaned up\n const unsubscribes = source.map((source) =>\n source.subscribe(() => {\n // If any source changes, re-evaluate and notify\n subscriber(value());\n }),\n );\n\n return () => {\n for (const fn of unsubscribes) fn();\n };\n },\n });\n};\n","/** @format */\n\nimport type { Grain, Subscriber } from './grain';\n\n/**\n * A `derived` grain transforms the value of a source grain through a mapping\n * function, producing a new readonly grain of a potentially different type.\n * Like all grains, the value is read by calling it:\n *\n * ```ts\n * const count = grain(5);\n * const isEven = derived(count, n => n % 2 === 0);\n * const value = isEven(); // false\n * ```\n *\n * Reads are always synchronous — the mapping function is applied on the fly.\n * Subscribers are notified whenever the source grain changes.\n */\n\n/**\n * Creates a readonly grain derived from a source grain by applying a\n * transformation function to its value.\n *\n * @template V - The type of value held by the source grain.\n * @template R - The type of value produced by the transformation.\n *\n * @param {Grain<V>} source - The grain to derive from.\n * @param {(value: V) => R} run - A transformation applied to the source value.\n *\n * @returns {Grain<R>} A readonly grain whose value is the result of applying\n * `run` to the current value of `source`. Subscribers are notified whenever\n * the source grain changes.\n *\n * @example\n * ```ts\n * const count = grain(5);\n * const isEven = derived(count, n => n % 2 === 0);\n *\n * isEven.subscribe(value => console.log(`Is even: ${value}`));\n * count.set(3); // Logs: Is even: false\n * count.set(4); // Logs: Is even: true\n * ```\n */\nexport const derived = <V, R>(source: Grain<V>, run: (value: V) => R): Grain<R> => {\n return Object.assign(() => run(source()), {\n subscribe(subscriber: Subscriber<R>) {\n return source.subscribe((value) => {\n subscriber(run(value));\n });\n },\n });\n};\n","import type { Grain, Subscriber } from './grain';\n\n/**\n * A `flattened` grain unwraps a grain-of-a-grain into a single grain,\n * subscribing to whichever inner grain is currently held by the outer grain.\n * Like all grains, the value is read by calling it:\n *\n * ```ts\n * const a = grain(1);\n * const b = grain(2);\n * const source = grain(a);\n * const flat = flattened(source);\n *\n * flat(); // 1\n * source.set(b);\n * flat(); // 2\n * ```\n *\n * When the outer grain changes, the subscription to the previous inner grain\n * is cleaned up and a new one is established. Both subscriptions are severed\n * when the returned unsubscribe function is called.\n */\n\n/**\n * Flattens a grain holding another grain into a single readonly grain\n * that reflects the current inner grain's value.\n *\n * @template V - The type of value held by the inner grain.\n *\n * @param {Grain<Grain<V>>} nested - A grain whose value is itself a grain.\n *\n * @returns {Grain<V>} A readonly grain reflecting the current value of\n * whichever inner grain `nested` currently holds. Subscribers are notified\n * when either the inner grain's value changes or the outer grain switches\n * to a new inner grain.\n *\n * @example\n * ```ts\n * const a = grain(1);\n * const b = grain(2);\n * const source = grain(a);\n * const flat = flattened(source);\n *\n * flat.subscribe(value => console.log(value));\n * a.set(10); // Logs: 10\n * source.set(b); // Logs: 2\n * b.set(20); // Logs: 20\n * ```\n */\nexport const flattened = <V>(nested: Grain<Grain<V>>): Grain<V> => {\n return Object.assign(() => nested()(), {\n subscribe: (subscriber: Subscriber<V>) => {\n let innerUnsubscribe = nested().subscribe(subscriber);\n\n // The outer subscription updates the grain and the inner\n // subscribers and unsubscribe, basically proxying the\n // grain from nested to source\n const outerUnsubscribe = nested.subscribe((newInnerGrain) => {\n innerUnsubscribe(); // Clean up the old inner subscription\n innerUnsubscribe = newInnerGrain.subscribe(subscriber);\n subscriber(newInnerGrain()); // Emit the new value immediately\n });\n\n return () => {\n innerUnsubscribe();\n outerUnsubscribe();\n };\n },\n });\n};\n","/** @format */\n\n/**\n * A `Grain` or `WritableGrain` is a reactive primitive capturing a\n * value via closure. It is basically a getter function accessing the\n * value, with additional methods bolted on.\n *\n * A `Grain`'s value can be read by calling it. It will always return\n * a up to date value, as all values are read synchronously.\n *\n * ```ts\n * const count = grain(0);\n * const value = count(); // value = 0\n * ```\n *\n * This is a core principle of grains & nord.\n *\n * To update the value of a grain, the `set` and `update` methods\n * can be used. Any update to the value is run through the\n * compare fn to determine if subscribers should be notified.\n * If yes, the subscribers are notified in order of subscription.\n */\n\n/**\n * Fn signature used to describe the compareFn used by grains\n * to check for equality. Receives a snapshot of the current and next\n * state. Return false to indicate that the values differ and should\n * trigger an update\n */\ntype CompareFn<V = unknown> = (current: V, next: V) => boolean;\nconst defaultCompareFn = <V = unknown>(current: V, next: V) => Object.is(current, next);\n\n/**\n * A `subscriber` is a callback added when subscribing to a `grain`, allowing to react\n * to changes in the source `grain`s value.\n */\nexport type Subscriber<V = unknown> = (value: V) => void;\n\n/**\n * Function returned by the `subscribe` method of a `grain`, allowing to\n * unsubscribe from listening to changes in the `grain`s value\n */\nexport type Unsubscribe = () => void;\n\n/**\n * The readonly version of a `grain` allows to read the value synchronous as well\n * as subscribe to changes in the `grains` value.\n */\nexport type Grain<V = unknown> = {\n (): V;\n subscribe: (subscriber: Subscriber<V>) => Unsubscribe;\n};\n\n/**\n * The writable version of a `grain` allows to set and update the value in addition\n * to reading and subscribing. The value's are set synchronously.\n */\nexport type WritableGrain<V> = Grain<V> & {\n set: (next: V) => void;\n update: (run: (current: V) => V) => void;\n};\n\n/**\n * Creates a reactive writable grain.\n * A writable grain represents a piece of reactive state\n * that can be subscribed to and updated.\n *\n * @template V - The type of value the grain will hold.\n *\n * @param {V} start - The initial value of the grain.\n * @param {CompareFn<V>} [compareFunc] - An optional function to determine\n * if the value has changed. Defaults to Object.is(). To indicate change, the fn\n * should return `false`\n *\n * @returns {WritableGrain<V>} An fn representing the grain value as a getter.\n * It contains methods to set & update the value as well as subscribe to changes.\n * Grains are always synchronous, there is no batching. To retrieve the value of\n * a grain, it is called like a function.\n *\n * The returned writable grain has the following methods:\n * - `set(value: V)`: Sets a new value for the grain.\n * - `subscribe(subscriber: Subscriber<V>)`: Subscribes to changes.\n * Returns a function to unsubscribe the passed subscriber.\n * - `update(updater: (current: V) => V)`: Updates the value using an updater function.\n *\n * @example\n * ```ts\n * // Setting up a simple subscription and unsubscribing\n * const count = grain(10);\n *\n * const unsubscribe = count.subscribe(value => console.log(value));\n * count.set(20); // Logs: 20\n * unsubscribe(); // Unsubscribes the logging function\n * ```\n *\n * @example\n * ```ts\n * // Updating the grain based on it's current state\n * const count = grain(0);\n *\n * count.subscribe(value => console.log(`Count is now: ${value}`));\n * count.update(currentCount => currentCount + 1); // Logs: Count is now: 1\n * count.update(currentCount => currentCount + 2); // Logs: Count is now: 3\n * ```\n */\nexport const grain = <V = unknown>(start: V, compareFunc: CompareFn<V> = defaultCompareFn): WritableGrain<V> => {\n let _value = start;\n const consumers = new Set<Subscriber<V>>();\n\n const notifyConsumers = () => {\n for (const consumer of Array.from(consumers)) consumer(_value);\n };\n\n const set = (newValue: V) => {\n if (!compareFunc(_value, newValue)) {\n _value = newValue;\n notifyConsumers();\n }\n };\n\n const update = (updater: (current: V) => V) => set(updater(_value));\n\n const subscribe = (subscriber: Subscriber<V>) => {\n consumers.add(subscriber);\n return () => consumers.delete(subscriber);\n };\n\n return Object.assign(() => _value, { set, update, subscribe });\n};\n","/** @format */\n\nimport type { Grain } from './grain';\n\n/**\n * Wraps a (Writable) Grain and exposes it as a readonly variant.\n * Can be called directly to retrieve the value, but no update is\n * possible through the returned value. A grain in its fundamental\n * signature represents a `subscribable`.\n *\n * @template V - The type of value the grain will hold,\n * inferred from the source grain.\n * @param { Grain<V> } source - The grain to shadow.\n * @returns { Grain<V> } - A readonly Grain<V>\n */\nexport const readonly = <V>(source: Grain<V>): Grain<V> => {\n return Object.assign(() => source(), {\n subscribe: source.subscribe,\n });\n};\n","import { type Grain, type WritableGrain, derived, grain } from '@grainular/grains';\nimport { createDirective } from '@grainular/nord';\nimport { getBinding } from './value-binding';\n\ntype ControlBindingOptions = {\n updateOn?: 'change' | 'input' | 'blur';\n};\n\nexport type Control<V = unknown> = {\n isControl: true;\n id: string;\n\n // Writable state\n value: WritableGrain<V>;\n errors: WritableGrain<string[]>;\n disabled: WritableGrain<boolean>;\n\n // Derived / event state\n isValid: Grain<boolean>;\n focused: WritableGrain<boolean>;\n touched: WritableGrain<boolean>;\n dirty: WritableGrain<boolean>;\n\n // Resets the value\n reset: () => void;\n\n // The directive used to bind\n // to the input element, using\n // a event\n bind: (options?: ControlBindingOptions) => ReturnType<typeof createDirective>;\n};\n\nconst handleNodeDisabledState = (node: Element, disabled: Grain<boolean>) => {\n disabled() ? node.setAttribute('disabled', '') : node.removeAttribute('disabled');\n\n return disabled.subscribe((state) => {\n state ? node.setAttribute('disabled', '') : node.removeAttribute('disabled');\n });\n};\n\nconst handleNodeFocusState = (node: Element, setTouched: () => void, setFocused: () => void, blur: () => void) => {\n const handler = (event: Event) => {\n if (event.type === 'focus') {\n setFocused();\n }\n\n if (event.type === 'blur') {\n setTouched();\n blur();\n }\n };\n\n node.addEventListener('focus', handler);\n node.addEventListener('blur', handler);\n\n return () => {\n node.removeEventListener('focus', handler);\n node.removeEventListener('blur', handler);\n };\n};\n\nconst handleNodeValueBinding = <V>(node: Element, value: WritableGrain<V>, event: string, setDirty: () => void) => {\n const { get, set } = getBinding(node);\n set(value());\n\n const handler = () => value.set(get() as V);\n node.addEventListener(event, handler);\n\n const cleanup = value.subscribe((value) => {\n setDirty();\n set(value);\n });\n\n return () => {\n node.removeEventListener(event, handler);\n cleanup();\n };\n};\n\n// Function to set up the control binding\n// to the control node. This is will be a\nconst createControlBinding = <V>(\n { updateOn: event }: Required<ControlBindingOptions>,\n setTouched: () => void,\n setFocused: () => void,\n setDirty: () => void,\n blur: () => void,\n disabled: Grain<boolean>,\n value: WritableGrain<V>,\n) => {\n return createDirective((node) => {\n // The bindings between the node and the state\n // needs to track multiple different states and\n // attributes.\n const resolveDisabledState = handleNodeDisabledState(node, disabled);\n const resolveFocusState = handleNodeFocusState(node, setTouched, setFocused, blur);\n const resolveValueBinding = handleNodeValueBinding(node, value, event, setDirty);\n\n return () => {\n resolveDisabledState();\n resolveFocusState();\n resolveValueBinding();\n };\n });\n};\n\n/**\n * Method to create a reactive control with\n * methods to retrieve the value and create\n * a binding\n * @param value\n */\nexport const control = <V>(initialValue: V): Control<V> => {\n const value = grain(initialValue);\n const errors = grain<string[]>([]);\n const disabled = grain(false);\n\n const isValid = derived(errors, (errors) => errors.length === 0);\n const touched = grain(false);\n const focused = grain(false);\n const dirty = grain(false);\n\n const reset = () => {\n errors.set([]);\n touched.set(false);\n focused.set(false);\n dirty.set(false);\n value.set(initialValue);\n };\n\n const binding = (options: Required<ControlBindingOptions>) => {\n return createControlBinding<V>(\n options,\n () => touched.set(true),\n () => focused.set(true),\n () => dirty.set(true),\n () => focused.set(false),\n disabled,\n value,\n );\n };\n\n return {\n id: crypto.randomUUID(),\n isControl: true,\n value,\n errors,\n disabled,\n isValid,\n touched,\n focused,\n dirty,\n reset,\n bind: (options: ControlBindingOptions = {}) => {\n return binding({ updateOn: 'input', ...options });\n },\n };\n};\n","import { type Grain, combined, derived, flattened } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaErrors = <T>(schema: FormSchema<T>): Grain<string[]> => {\n // Normalize the nullable errors state\n if ('isControl' in schema) {\n return derived(schema.errors, (errors) => errors);\n }\n\n // Lists are deeply flattened and normalized\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n const errorGrains = schemas.map((s) => deriveSchemaErrors(s));\n return derived(combined(errorGrains), (nested) => nested.flat());\n }),\n );\n }\n\n // Anything else is flattened\n return derived(\n combined(\n Object.values(schema).map((subSchema) => {\n return deriveSchemaErrors(subSchema);\n }),\n ),\n (nested) => nested.flat(),\n );\n};\n","import { type Grain, combined, derived, flattened } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaTouched = <T>(schema: FormSchema<T>): Grain<boolean[]> => {\n // Normalize the nullable errors state\n if ('isControl' in schema) {\n return derived(schema.touched, (errors) => [errors]);\n }\n\n // Lists are deeply flattened and normalized\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n return schemas.map((s) => deriveSchemaTouched(s));\n }),\n );\n }\n\n // Anything else is flattened\n return derived(\n combined(\n Object.values(schema).map((subSchema) => {\n return deriveSchemaTouched(subSchema);\n }),\n ),\n (nested) => nested.flat(),\n );\n};\n","import { type Grain, combined, derived, flattened, readonly } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaValue = <T>(schema: FormSchema<T>): Grain<T> => {\n // Handle pure controls by returning the\n // direct control value\n if ('isControl' in schema) return readonly(schema.value);\n\n // We check for the 'controls' grain and array methods\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n return combined(schemas.map(deriveSchemaValue));\n }),\n );\n }\n\n // Get all the child value grains\n const keyedValues = Object.entries(schema).map(([key, subSchema]) => {\n return { key, grain: deriveSchemaValue(subSchema) };\n });\n\n // Extract just the grains for 'combined'\n return derived(combined(keyedValues.map((entry) => entry.grain)), (values) => {\n // Reconstruct the object using the original keys and the new values\n return values.reduce((acc, val, index) => {\n const key = keyedValues[index].key;\n // @ts-expect-error\n acc[key] = val;\n return acc;\n }, {} as T);\n }) as Grain<T>;\n};\n","import { type WritableGrain, grain } from '@grainular/grains';\nimport { type FormSchema, createFormSchema } from './form-schema';\n\nexport type ControlList<T> = {\n isControlList: true;\n controls: WritableGrain<FormSchema<T>[]>;\n add: (value: T) => void;\n remove: (control: FormSchema<T>) => void;\n at: (idx: number) => FormSchema<T> | undefined;\n\n reset: () => void;\n set: (value: T[]) => void;\n};\n\nexport const controlList = <T>(initialValues: T[]): ControlList<T> => {\n const initialSchemas = initialValues.map((v) => createFormSchema(v));\n const controls = grain(initialSchemas);\n\n return {\n isControlList: true,\n controls,\n\n // Add: Create the schema for the new value and push it to the state\n add: (value: T) => {\n const schema = createFormSchema(value);\n controls.update((current) => [...current, schema]);\n },\n\n // Remove: Filter the array by comparator\n remove: (control: FormSchema<T>) => {\n controls.update((current) => {\n return [...current.filter((c) => c !== control)];\n });\n },\n\n // At: Access the reactive schema at a specific index\n // (Note: This returns the SCHEMA, so you can do .at(0).value() or .at(0).bind())\n at: (idx: number) => {\n return controls()[idx];\n },\n\n set: (value: T[]) => {\n // No reconciliation here, as we never know how the values\n // passed actually relate. Better to just overwrite completely\n const updatedSchema = value.map((value) => createFormSchema(value));\n controls.set(updatedSchema);\n },\n\n // Reset's the control to it's\n // initial value\n reset: () => {\n controls.set(initialSchemas);\n },\n };\n};\n","import { type Control, control } from './control';\nimport { type ControlList, controlList } from './control-list';\n\n// Helper to stop recursion on simple types (including Date)\ntype Primitive = string | number | boolean | Date | null | undefined;\n\n// Providing a type that maps models\n// into a schema using lists and controls\nexport type FormSchema<T> = [T] extends [Primitive]\n ? Control<T>\n : T extends Array<infer U>\n ? ControlList<U>\n : { [K in keyof T]: FormSchema<T[K]> };\n\nexport const createFormSchema = <T>(value: T): FormSchema<T> => {\n // Lists are parsed out\n if (Array.isArray(value)) {\n return controlList(value) as FormSchema<T>;\n }\n\n // Objects are converted to a nested tree\n if (value !== null && typeof value === 'object' && !(value instanceof Date)) {\n const groupEntries = Object.entries(value).map(([key, val]) => {\n return [key, createFormSchema(val)];\n });\n return Object.fromEntries(groupEntries) as FormSchema<T>;\n }\n\n // C) It is a Primitive -> Create a Leaf Control\n // We wrap the raw value in a grain to make it reactive\n return control(value) as FormSchema<T>;\n};\n","import type { FormSchema } from './form-schema';\n\nexport const setFormValue = <T>(schema: FormSchema<T>, model: T) => {\n // If we reached a leaf or a single control, we simply\n // set the value.\n if ('isControl' in schema) {\n schema.value.set(model);\n }\n\n // Lists have their own setter fn\n if ('isControlList' in schema && Array.isArray(model)) {\n schema.set(model);\n }\n\n if (typeof model === 'object' && model !== null) {\n for (const [key, value] of Object.entries(model)) {\n if (key in schema) {\n //@ts-expect-error Typescript unable to correctly nest the type here\n setFormValue(schema[key], value);\n }\n }\n }\n};\n","import type { Control } from './control';\nimport type { FormSchema } from './form-schema';\n\nexport const iterateSchema = <T>(schema: FormSchema<T>, run: (control: Control) => void) => {\n // If just control, run callback\n if ('isControl' in schema) {\n return run(schema as Control);\n }\n\n // Lists are deeply iterated\n if ('isControlList' in schema) {\n for (const control of schema.controls()) {\n iterateSchema(control, run);\n }\n return;\n }\n\n for (const value of Object.values(schema)) {\n iterateSchema(value, run);\n }\n};\n","import type { FormSchema } from './form-schema';\nimport { iterateSchema } from './iterate-schema';\n\nexport const touchAll = <T>(controls: FormSchema<T>) => {\n iterateSchema(controls, (control) => control.touched.set(true));\n};\n","import { type Grain, combined, derived } from '@grainular/grains';\nimport { deriveSchemaErrors } from './derive-schema-errors';\nimport { deriveSchemaTouched } from './derive-schema-touched';\nimport { deriveSchemaValue } from './derive-schema-value';\nimport { type FormSchema, createFormSchema } from './form-schema';\nimport { setFormValue } from './handle-form-value';\nimport { iterateSchema } from './iterate-schema';\nimport { touchAll } from './touch-all';\n\nexport type Form<T> = {\n value: Grain<T>;\n controls: FormSchema<T>;\n errors: Grain<string[]>;\n isValid: Grain<boolean>;\n isTouched: Grain<boolean>;\n validate: () => boolean;\n set: (value: T) => void;\n reset: () => void;\n};\n\n/**\n *\n * @param model\n * @param schema\n */\nexport const form = <T extends Record<PropertyKey, unknown>>(\n model: T,\n schema: (state: FormSchema<T>) => void = () => {},\n): Form<T> => {\n const controls = createFormSchema(model);\n const value = deriveSchemaValue(controls);\n const errors = deriveSchemaErrors(controls);\n const isValid = derived(errors, (errors) => errors.length === 0);\n\n // Touch states\n const touchStates = deriveSchemaTouched(controls);\n const isTouched = derived(touchStates, (states) => states.some(Boolean));\n\n // Create the form setter and reset fn\n const set = (value: T) => setFormValue(controls, value);\n const reset = () => iterateSchema(controls, (control) => control.reset());\n const validate = () => {\n touchAll(controls);\n schema(controls);\n return errors().length === 0;\n };\n\n // Track value changes and run the schema fn\n // whenever the value changes and once on creation\n schema(controls);\n combined([value, touchStates]).subscribe(() => schema(controls));\n\n // Return the created form object\n return { controls, value, errors, isValid, isTouched, set, reset, validate };\n};\n","import { type Grain, combined, derived } from '@grainular/grains';\nimport { $if, type ComponentFragment } from '@grainular/nord';\nimport type { Control } from '../lib/control';\n\ntype ErrorRenderer = (errors: Grain<string>) => ComponentFragment;\ntype ControlErrorOptions = {\n showOn?: 'touched' | 'always';\n};\n\nexport const $controlErrors = <V>(\n control: Control<V>,\n renderer: ErrorRenderer,\n options: ControlErrorOptions = { showOn: 'touched' },\n) => {\n // We create a derived state that only emits errors when the conditions are met.\n // Otherwise, it emits null, which causes $if to unmount the view.\n const visibleErrors = derived(combined([control.errors, control.touched]), ([errors, touched]) => {\n // 1. If there are no errors, render nothing\n if (!errors || errors.length === 0) {\n return null;\n }\n\n // 2. Check visibility conditions\n const shouldShow = options.showOn === 'always' || touched;\n\n // 3. Return errors if visible, otherwise null\n return shouldShow ? errors : null;\n });\n\n // Delegate to the existing $if structural directive\n return $if(derived(visibleErrors, (value) => (value ?? []).length > 0)).$then(() =>\n renderer(derived(visibleErrors, (errors) => (errors ?? []).join(', '))),\n );\n};\n","import type { WritableGrain } from '@grainular/grains';\n\ntype HasError = { errors: WritableGrain<string[]> };\nexport const setControlError = (control: HasError, message: string) => {\n control.errors.update((errors) => {\n return [...new Set([...(errors ?? []), message])];\n });\n};\n\nexport const clearControlError = (control: HasError, message: string) => {\n control.errors.update((errors) => {\n return [...new Set([...(errors ?? []).filter((msg) => msg !== message)])];\n });\n};\n","import type { Control } from '../lib/control';\nimport { clearControlError, setControlError } from './core';\n\ntype ValidatorData<T> = T & { message: string };\ntype ValidatorFn<Opts, T> = (\n control: Control<T>,\n setError: () => void,\n clearError: () => void,\n opts: Omit<ValidatorData<Opts>, 'message'>,\n) => void;\n\n// We need to provide this type explicitly to\n// avoid invariance problems. Sucks but that's\n// the price to pay for type safe validators.\nexport type Validator<Opts, T> = <V extends T>(control: Control<V>, opts: ValidatorData<Opts>) => void;\n\nexport const createValidator = <Opts extends Record<PropertyKey, unknown>, T>(\n validatorFn: ValidatorFn<Opts, T>,\n): Validator<Opts, T> => {\n return <V extends T>(control: Control<V>, { message, ...opts }: ValidatorData<Opts>) => {\n // Casting the control makes it work. This should\n // be fine, as we only ever read the value of the\n // control.\n const castControl = control as unknown as Control<T>;\n\n const setError = () => setControlError(castControl, message);\n const clearError = () => clearControlError(castControl, message);\n if (control.touched()) {\n validatorFn(castControl, setError, clearError, opts);\n }\n };\n};\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nconst EMAIL_REGEX =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n\nexport const email: Validator<Record<string, never>, string | null> = createValidator(\n (control: Control<string | null>, setError, clearError) => {\n const value = control.value();\n\n // Empty values are valid (handled by 'required')\n if (value === null || value === '') {\n return clearError();\n }\n\n EMAIL_REGEX.test(value) ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const max: Validator<{ max: number }, number | null> = createValidator(\n (control: Control<number | null>, setError, clearError, { max }) => {\n const value = control.value();\n\n if (value === null || typeof value !== 'number') return clearError();\n value <= max ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { createValidator, type Validator } from './create-validator';\n\nexport const maxLength: Validator<{ max: number }, unknown[]> = createValidator(\n (control: Control<unknown[]>, setError, clearError, { max }) => {\n const value = control.value();\n\n if (!Array.isArray(value) || (Array.isArray(value) && value.length <= max)) return clearError();\n value.length > max && setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const min: Validator<{ min: number }, number | null> = createValidator(\n (control: Control<number | null>, setError, clearError, { min }) => {\n const value = control.value();\n\n if (value === null || typeof value !== 'number') return clearError();\n value >= min ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { createValidator, type Validator } from './create-validator';\n\nexport const minLength: Validator<{ min: number }, unknown[]> = createValidator(\n (control: Control<unknown[]>, setError, clearError, { min }) => {\n const value = control.value();\n\n if (!Array.isArray(value) || (Array.isArray(value) && value.length >= min)) return clearError();\n value.length < min && setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const pattern: Validator<{ regex: RegExp }, string | null> = createValidator(\n (control: Control<string | null>, setError, clearError, { regex }) => {\n const value = control.value();\n\n // If the value is empty/null, we clear the error.\n // We leave emptiness checks to the 'required' validator.\n if (value === null || value === '') {\n return clearError();\n }\n\n // Test the regex against the value\n regex.test(value) ? clearError() : setError();\n },\n);\n","import { createValidator } from './create-validator';\n\nexport const required = createValidator((control, setError, clearError) => {\n const value = control.value();\n\n if (typeof value !== 'string') {\n return value ? clearError() : setError();\n }\n\n value.trim() !== '' ? clearError() : setError();\n});\n","import type { ControlList } from '../lib/control-list';\nimport type { FormSchema } from '../lib/form-schema';\n\nexport const validateEach = <T>(control: ControlList<T>, schemaFn: (schema: FormSchema<T>, idx: number) => void) => {\n control.controls().forEach((control, idx) => schemaFn(control, idx));\n};\n"]}
@@ -0,0 +1,3 @@
1
+ (()=>{var{defineProperty:p,getOwnPropertyNames:b,getOwnPropertyDescriptor:q}=Object,s=Object.prototype.hasOwnProperty;function v(r){return this[r]}var A=(r)=>{var o=(x??=new WeakMap).get(r),e;if(o)return o;if(o=p({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function"){for(var m of b(r))if(!s.call(o,m))p(o,m,{get:v.bind(r,m),enumerable:!(e=q(r,m))||e.enumerable})}return x.set(r,o),o},x;var C=(r)=>r;function F(r,o){this[r]=C.bind(null,o)}var $=(r,o)=>{for(var e in o)p(r,e,{get:o[e],enumerable:!0,configurable:!0,set:F.bind(o,e)})};var t=((r)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(o,e)=>(typeof require<"u"?require:o)[e]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var j={};$(j,{validateEach:()=>V.validateEach,touchAll:()=>n.touchAll,required:()=>L.required,pattern:()=>E.pattern,minLength:()=>u.minLength,min:()=>g.min,maxLength:()=>y.maxLength,max:()=>h.max,form:()=>l.form,email:()=>d.email,createValidator:()=>c.createValidator,control:()=>a.control,bind:()=>f.bind,$controlErrors:()=>i.$controlErrors});})();
2
+
3
+ //# debugId=F5668FC7CE3B5B3464756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "F5668FC7CE3B5B3464756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1,2 @@
1
+ 'use strict';var nord=require('@grainular/nord'),grains=require('@grainular/grains');var M=new Map([[t=>t instanceof HTMLInputElement&&t.type==="checkbox",t=>{let r=t;return {get:()=>r.checked,set:e=>{r.checked=!!e;}}}],[t=>t instanceof HTMLInputElement&&t.type==="radio",t=>{let r=t;return {get:()=>r.value,set:e=>{r.checked=e===r.value;}}}],[t=>t instanceof HTMLInputElement&&t.type==="file",t=>{let r=t;return {get:()=>r.files,set:()=>{}}}],[t=>t instanceof HTMLSelectElement&&t.type==="select-multiple",t=>{let r=t;return {get:()=>Array.from(r.selectedOptions,e=>e.value),set:e=>{queueMicrotask(()=>{let o=Array.isArray(e)?e:[e];for(let n of r.options)n.selected=o.includes(n.value);});}}}],[t=>t instanceof HTMLSelectElement,t=>{let r=t;return {get:()=>Array.from(r.selectedOptions,e=>e.value).at(0),set:e=>{queueMicrotask(()=>{for(let o of r.options)o.selected=e===o.value;});}}}],[t=>t instanceof HTMLInputElement&&(t.type==="number"||t.type==="range"),t=>{let r=t;return {get:()=>r.value===""?null:r.valueAsNumber,set:e=>{r.value=String(e??"");}}}],[t=>t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement,t=>{let r=t;return {get:()=>r.value,set:e=>{r.value=String(e??"");}}}]]),b=t=>{for(let[r,e]of M)if(r(t))return e(t);return {get:()=>null,set:()=>{}}};var B=(t,r="input")=>nord.createDirective(e=>{let{get:o,set:n}=b(e);n(t());let i=t.subscribe(l=>n(l)),a=()=>t.set(o());return e.addEventListener(r,a),()=>{e.removeEventListener(r,a),i();}});var I=(t,r)=>(r()?t.setAttribute("disabled",""):t.removeAttribute("disabled"),r.subscribe(e=>{e?t.setAttribute("disabled",""):t.removeAttribute("disabled");})),j=(t,r,e,o)=>{let n=i=>{i.type==="focus"&&e(),i.type==="blur"&&(r(),o());};return t.addEventListener("focus",n),t.addEventListener("blur",n),()=>{t.removeEventListener("focus",n),t.removeEventListener("blur",n);}},R=(t,r,e,o)=>{let{get:n,set:i}=b(t);i(r());let a=()=>r.set(n());t.addEventListener(e,a);let l=r.subscribe(c=>{o(),i(c);});return ()=>{t.removeEventListener(e,a),l();}},z=({updateOn:t},r,e,o,n,i,a)=>nord.createDirective(l=>{let c=I(l,i),y=j(l,r,e,n),m=R(l,a,t,o);return ()=>{c(),y(),m();}}),C=t=>{let r=grains.grain(t),e=grains.grain([]),o=grains.grain(false),n=grains.derived(e,m=>m.length===0),i=grains.grain(false),a=grains.grain(false),l=grains.grain(false),c=()=>{e.set([]),i.set(false),a.set(false),l.set(false),r.set(t);},y=m=>z(m,()=>i.set(true),()=>a.set(true),()=>l.set(true),()=>a.set(false),o,r);return {id:crypto.randomUUID(),isControl:true,value:r,errors:e,disabled:o,isValid:n,touched:i,focused:a,dirty:l,reset:c,bind:(m={})=>y({updateOn:"input",...m})}};var T=t=>"isControl"in t?grains.derived(t.errors,r=>r):"isControlList"in t?grains.flattened(grains.derived(t.controls,r=>{let e=r.map(o=>T(o));return grains.derived(grains.combined(e),o=>o.flat())})):grains.derived(grains.combined(Object.values(t).map(r=>T(r))),r=>r.flat());var g=t=>"isControl"in t?grains.derived(t.touched,r=>[r]):"isControlList"in t?grains.flattened(grains.derived(t.controls,r=>r.map(e=>g(e)))):grains.derived(grains.combined(Object.values(t).map(r=>g(r))),r=>r.flat());var h=t=>{if("isControl"in t)return grains.readonly(t.value);if("isControlList"in t)return grains.flattened(grains.derived(t.controls,e=>grains.combined(e.map(h))));let r=Object.entries(t).map(([e,o])=>({key:e,grain:h(o)}));return grains.derived(grains.combined(r.map(e=>e.grain)),e=>e.reduce((o,n,i)=>{let a=r[i].key;return o[a]=n,o},{}))};var A=t=>{let r=t.map(o=>u(o)),e=grains.grain(r);return {isControlList:true,controls:e,add:o=>{let n=u(o);e.update(i=>[...i,n]);},remove:o=>{e.update(n=>[...n.filter(i=>i!==o)]);},at:o=>e()[o],set:o=>{let n=o.map(i=>u(i));e.set(n);},reset:()=>{e.set(r);}}};var u=t=>{if(Array.isArray(t))return A(t);if(t!==null&&typeof t=="object"&&!(t instanceof Date)){let r=Object.entries(t).map(([e,o])=>[e,u(o)]);return Object.fromEntries(r)}return C(t)};var V=(t,r)=>{if("isControl"in t&&t.value.set(r),"isControlList"in t&&Array.isArray(r)&&t.set(r),typeof r=="object"&&r!==null)for(let[e,o]of Object.entries(r))e in t&&V(t[e],o);};var f=(t,r)=>{if("isControl"in t)return r(t);if("isControlList"in t){for(let e of t.controls())f(e,r);return}for(let e of Object.values(t))f(e,r);};var S=t=>{f(t,r=>r.touched.set(true));};var _=(t,r=()=>{})=>{let e=u(t),o=h(e),n=T(e),i=grains.derived(n,p=>p.length===0),a=g(e),l=grains.derived(a,p=>p.some(Boolean)),c=p=>V(e,p),y=()=>f(e,p=>p.reset()),m=()=>(S(e),r(e),n().length===0);return r(e),grains.combined([o,a]).subscribe(()=>r(e)),{controls:e,value:o,errors:n,isValid:i,isTouched:l,set:c,reset:y,validate:m}};var Q=(t,r,e={showOn:"touched"})=>{let o=grains.derived(grains.combined([t.errors,t.touched]),([n,i])=>!n||n.length===0?null:e.showOn==="always"||i?n:null);return nord.$if(grains.derived(o,n=>(n??[]).length>0)).$then(()=>r(grains.derived(o,n=>(n??[]).join(", "))))};var k=(t,r)=>{t.errors.update(e=>[...new Set([...e??[],r])]);},w=(t,r)=>{t.errors.update(e=>[...new Set([...(e??[]).filter(o=>o!==r)])]);};var s=t=>(r,{message:e,...o})=>{let n=r,i=()=>k(n,e),a=()=>w(n,e);r.touched()&&t(n,i,a,o);};var Y=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,tt=s((t,r,e)=>{let o=t.value();if(o===null||o==="")return e();Y.test(o)?e():r();});var rt=s((t,r,e,{max:o})=>{let n=t.value();if(n===null||typeof n!="number")return e();n<=o?e():r();});var et=s((t,r,e,{max:o})=>{let n=t.value();if(!Array.isArray(n)||Array.isArray(n)&&n.length<=o)return e();n.length>o&&r();});var ot=s((t,r,e,{min:o})=>{let n=t.value();if(n===null||typeof n!="number")return e();n>=o?e():r();});var nt=s((t,r,e,{min:o})=>{let n=t.value();if(!Array.isArray(n)||Array.isArray(n)&&n.length>=o)return e();n.length<o&&r();});var it=s((t,r,e,{regex:o})=>{let n=t.value();if(n===null||n==="")return e();o.test(n)?e():r();});var at=s((t,r,e)=>{let o=t.value();if(typeof o!="string")return o?e():r();o.trim()!==""?e():r();});var st=(t,r)=>{t.controls().forEach((e,o)=>r(e,o));};exports.$controlErrors=Q;exports.bind=B;exports.control=C;exports.createValidator=s;exports.email=tt;exports.form=_;exports.max=rt;exports.maxLength=et;exports.min=ot;exports.minLength=nt;exports.pattern=it;exports.required=at;exports.touchAll=S;exports.validateEach=st;//# sourceMappingURL=index.cjs.map
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/value-binding.ts","../../src/directives/bind.directive.ts","../../src/lib/control.ts","../../src/lib/derive-schema-errors.ts","../../src/lib/derive-schema-touched.ts","../../src/lib/derive-schema-value.ts","../../src/lib/control-list.ts","../../src/lib/form-schema.ts","../../src/lib/handle-form-value.ts","../../src/lib/iterate-schema.ts","../../src/lib/touch-all.ts","../../src/lib/form.ts","../../src/structs/control-errors.struct.ts","../../src/validators/core.ts","../../src/validators/create-validator.ts","../../src/validators/email.ts","../../src/validators/max.ts","../../src/validators/max-length.ts","../../src/validators/min.ts","../../src/validators/min-length.ts","../../src/validators/pattern.ts","../../src/validators/required.ts","../../src/validators/validate-each.ts"],"names":["bindings","node","input","val","select","opt","values","option","getBinding","predicate","factory","bind","value","event","createDirective","get","set","cleanup","handler","handleNodeDisabledState","disabled","state","handleNodeFocusState","setTouched","setFocused","blur","handleNodeValueBinding","setDirty","createControlBinding","resolveDisabledState","resolveFocusState","resolveValueBinding","control","initialValue","grain","errors","isValid","derived","touched","focused","dirty","reset","binding","options","deriveSchemaErrors","schema","flattened","schemas","errorGrains","s","combined","nested","subSchema","deriveSchemaTouched","deriveSchemaValue","readonly","keyedValues","key","entry","acc","index","controlList","initialValues","initialSchemas","v","createFormSchema","controls","current","c","idx","updatedSchema","groupEntries","setFormValue","model","iterateSchema","run","touchAll","form","touchStates","isTouched","states","validate","$controlErrors","renderer","visibleErrors","$if","setControlError","message","clearControlError","msg","createValidator","validatorFn","opts","castControl","setError","clearError","EMAIL_REGEX","email","max","maxLength","min","minLength","pattern","regex","required","validateEach","schemaFn"],"mappings":"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","file":"index.cjs","sourcesContent":["// --- Interfaces ---\ntype Binding = {\n get: () => unknown;\n set: (value: unknown) => void;\n};\n\ntype Predicate = (node: Element) => boolean;\ntype Factory = (node: Element) => Binding;\n\n// --- The Dictionary ---\nconst bindings = new Map<Predicate, Factory>([\n // 1. Checkbox\n [\n (node) => node instanceof HTMLInputElement && node.type === 'checkbox',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.checked,\n set: (val) => {\n input.checked = Boolean(val);\n },\n };\n },\n ],\n // 1.5 -> Radio\n [\n (node) => node instanceof HTMLInputElement && node.type === 'radio',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.value,\n set: (val) => {\n input.checked = val === input.value;\n },\n };\n },\n ],\n // 2. File Input (Read-Only)\n [\n (node) => node instanceof HTMLInputElement && node.type === 'file',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.files,\n set: () => {\n /* No-op: File inputs are security locked */\n },\n };\n },\n ],\n // 3. Multi-Select\n [\n (node) => node instanceof HTMLSelectElement && node.type === 'select-multiple',\n (node) => {\n const select = node as HTMLSelectElement;\n return {\n get: () => Array.from(select.selectedOptions, (opt) => opt.value),\n set: (val) => {\n queueMicrotask(() => {\n const values = Array.isArray(val) ? val : [val];\n for (const option of select.options) {\n option.selected = values.includes(option.value);\n }\n });\n },\n };\n },\n ],\n // 3.5 -> Single Select\n [\n (node) => node instanceof HTMLSelectElement,\n (node) => {\n const select = node as HTMLSelectElement;\n return {\n get: () => Array.from(select.selectedOptions, (opt) => opt.value).at(0),\n set: (val) => {\n queueMicrotask(() => {\n for (const option of select.options) {\n option.selected = val === option.value;\n }\n });\n },\n };\n },\n ],\n // 4. Numeric Inputs (Number & Range)\n [\n (node) => node instanceof HTMLInputElement && (node.type === 'number' || node.type === 'range'),\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => (input.value === '' ? null : input.valueAsNumber),\n set: (val) => {\n input.value = String(val ?? '');\n },\n };\n },\n ],\n // 5. Default Fallback (Text, Textarea, Single Select, etc.)\n [\n (node) => node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement,\n (node) => {\n // Safe to cast to generic input interface usually, or just use 'value' property\n const input = node as HTMLInputElement;\n return {\n get: () => input.value,\n set: (val) => {\n input.value = String(val ?? '');\n },\n };\n },\n ],\n]);\n\nexport const getBinding = (node: Element): Binding => {\n for (const [predicate, factory] of bindings) {\n if (predicate(node)) return factory(node);\n }\n // Fallback for non-form elements (or throw error)\n return { get: () => null, set: () => {} };\n};\n","import type { WritableGrain } from '@grainular/grains';\nimport { createDirective } from '@grainular/nord';\nimport { getBinding } from '../lib/value-binding';\n\nexport const bind = <V>(value: WritableGrain<V>, event: 'change' | 'input' | 'blur' = 'input') => {\n return createDirective((node) => {\n const { get, set } = getBinding(node);\n\n // Setter logic\n set(value());\n const cleanup = value.subscribe((value) => set(value));\n\n // Handler logic\n const handler = () => value.set(get() as V);\n node.addEventListener(event, handler);\n\n return () => {\n node.removeEventListener(event, handler);\n cleanup();\n };\n });\n};\n","import { type Grain, type WritableGrain, derived, grain } from '@grainular/grains';\nimport { createDirective } from '@grainular/nord';\nimport { getBinding } from './value-binding';\n\ntype ControlBindingOptions = {\n updateOn?: 'change' | 'input' | 'blur';\n};\n\nexport type Control<V = unknown> = {\n isControl: true;\n id: string;\n\n // Writable state\n value: WritableGrain<V>;\n errors: WritableGrain<string[]>;\n disabled: WritableGrain<boolean>;\n\n // Derived / event state\n isValid: Grain<boolean>;\n focused: WritableGrain<boolean>;\n touched: WritableGrain<boolean>;\n dirty: WritableGrain<boolean>;\n\n // Resets the value\n reset: () => void;\n\n // The directive used to bind\n // to the input element, using\n // a event\n bind: (options?: ControlBindingOptions) => ReturnType<typeof createDirective>;\n};\n\nconst handleNodeDisabledState = (node: Element, disabled: Grain<boolean>) => {\n disabled() ? node.setAttribute('disabled', '') : node.removeAttribute('disabled');\n\n return disabled.subscribe((state) => {\n state ? node.setAttribute('disabled', '') : node.removeAttribute('disabled');\n });\n};\n\nconst handleNodeFocusState = (node: Element, setTouched: () => void, setFocused: () => void, blur: () => void) => {\n const handler = (event: Event) => {\n if (event.type === 'focus') {\n setFocused();\n }\n\n if (event.type === 'blur') {\n setTouched();\n blur();\n }\n };\n\n node.addEventListener('focus', handler);\n node.addEventListener('blur', handler);\n\n return () => {\n node.removeEventListener('focus', handler);\n node.removeEventListener('blur', handler);\n };\n};\n\nconst handleNodeValueBinding = <V>(node: Element, value: WritableGrain<V>, event: string, setDirty: () => void) => {\n const { get, set } = getBinding(node);\n set(value());\n\n const handler = () => value.set(get() as V);\n node.addEventListener(event, handler);\n\n const cleanup = value.subscribe((value) => {\n setDirty();\n set(value);\n });\n\n return () => {\n node.removeEventListener(event, handler);\n cleanup();\n };\n};\n\n// Function to set up the control binding\n// to the control node. This is will be a\nconst createControlBinding = <V>(\n { updateOn: event }: Required<ControlBindingOptions>,\n setTouched: () => void,\n setFocused: () => void,\n setDirty: () => void,\n blur: () => void,\n disabled: Grain<boolean>,\n value: WritableGrain<V>,\n) => {\n return createDirective((node) => {\n // The bindings between the node and the state\n // needs to track multiple different states and\n // attributes.\n const resolveDisabledState = handleNodeDisabledState(node, disabled);\n const resolveFocusState = handleNodeFocusState(node, setTouched, setFocused, blur);\n const resolveValueBinding = handleNodeValueBinding(node, value, event, setDirty);\n\n return () => {\n resolveDisabledState();\n resolveFocusState();\n resolveValueBinding();\n };\n });\n};\n\n/**\n * Method to create a reactive control with\n * methods to retrieve the value and create\n * a binding\n * @param value\n */\nexport const control = <V>(initialValue: V): Control<V> => {\n const value = grain(initialValue);\n const errors = grain<string[]>([]);\n const disabled = grain(false);\n\n const isValid = derived(errors, (errors) => errors.length === 0);\n const touched = grain(false);\n const focused = grain(false);\n const dirty = grain(false);\n\n const reset = () => {\n errors.set([]);\n touched.set(false);\n focused.set(false);\n dirty.set(false);\n value.set(initialValue);\n };\n\n const binding = (options: Required<ControlBindingOptions>) => {\n return createControlBinding<V>(\n options,\n () => touched.set(true),\n () => focused.set(true),\n () => dirty.set(true),\n () => focused.set(false),\n disabled,\n value,\n );\n };\n\n return {\n id: crypto.randomUUID(),\n isControl: true,\n value,\n errors,\n disabled,\n isValid,\n touched,\n focused,\n dirty,\n reset,\n bind: (options: ControlBindingOptions = {}) => {\n return binding({ updateOn: 'input', ...options });\n },\n };\n};\n","import { type Grain, combined, derived, flattened } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaErrors = <T>(schema: FormSchema<T>): Grain<string[]> => {\n // Normalize the nullable errors state\n if ('isControl' in schema) {\n return derived(schema.errors, (errors) => errors);\n }\n\n // Lists are deeply flattened and normalized\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n const errorGrains = schemas.map((s) => deriveSchemaErrors(s));\n return derived(combined(errorGrains), (nested) => nested.flat());\n }),\n );\n }\n\n // Anything else is flattened\n return derived(\n combined(\n Object.values(schema).map((subSchema) => {\n return deriveSchemaErrors(subSchema);\n }),\n ),\n (nested) => nested.flat(),\n );\n};\n","import { type Grain, combined, derived, flattened } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaTouched = <T>(schema: FormSchema<T>): Grain<boolean[]> => {\n // Normalize the nullable errors state\n if ('isControl' in schema) {\n return derived(schema.touched, (errors) => [errors]);\n }\n\n // Lists are deeply flattened and normalized\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n return schemas.map((s) => deriveSchemaTouched(s));\n }),\n );\n }\n\n // Anything else is flattened\n return derived(\n combined(\n Object.values(schema).map((subSchema) => {\n return deriveSchemaTouched(subSchema);\n }),\n ),\n (nested) => nested.flat(),\n );\n};\n","import { type Grain, combined, derived, flattened, readonly } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaValue = <T>(schema: FormSchema<T>): Grain<T> => {\n // Handle pure controls by returning the\n // direct control value\n if ('isControl' in schema) return readonly(schema.value);\n\n // We check for the 'controls' grain and array methods\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n return combined(schemas.map(deriveSchemaValue));\n }),\n );\n }\n\n // Get all the child value grains\n const keyedValues = Object.entries(schema).map(([key, subSchema]) => {\n return { key, grain: deriveSchemaValue(subSchema) };\n });\n\n // Extract just the grains for 'combined'\n return derived(combined(keyedValues.map((entry) => entry.grain)), (values) => {\n // Reconstruct the object using the original keys and the new values\n return values.reduce((acc, val, index) => {\n const key = keyedValues[index].key;\n // @ts-expect-error\n acc[key] = val;\n return acc;\n }, {} as T);\n }) as Grain<T>;\n};\n","import { type WritableGrain, grain } from '@grainular/grains';\nimport { type FormSchema, createFormSchema } from './form-schema';\n\nexport type ControlList<T> = {\n isControlList: true;\n controls: WritableGrain<FormSchema<T>[]>;\n add: (value: T) => void;\n remove: (control: FormSchema<T>) => void;\n at: (idx: number) => FormSchema<T> | undefined;\n\n reset: () => void;\n set: (value: T[]) => void;\n};\n\nexport const controlList = <T>(initialValues: T[]): ControlList<T> => {\n const initialSchemas = initialValues.map((v) => createFormSchema(v));\n const controls = grain(initialSchemas);\n\n return {\n isControlList: true,\n controls,\n\n // Add: Create the schema for the new value and push it to the state\n add: (value: T) => {\n const schema = createFormSchema(value);\n controls.update((current) => [...current, schema]);\n },\n\n // Remove: Filter the array by comparator\n remove: (control: FormSchema<T>) => {\n controls.update((current) => {\n return [...current.filter((c) => c !== control)];\n });\n },\n\n // At: Access the reactive schema at a specific index\n // (Note: This returns the SCHEMA, so you can do .at(0).value() or .at(0).bind())\n at: (idx: number) => {\n return controls()[idx];\n },\n\n set: (value: T[]) => {\n // No reconciliation here, as we never know how the values\n // passed actually relate. Better to just overwrite completely\n const updatedSchema = value.map((value) => createFormSchema(value));\n controls.set(updatedSchema);\n },\n\n // Reset's the control to it's\n // initial value\n reset: () => {\n controls.set(initialSchemas);\n },\n };\n};\n","import { type Control, control } from './control';\nimport { type ControlList, controlList } from './control-list';\n\n// Helper to stop recursion on simple types (including Date)\ntype Primitive = string | number | boolean | Date | null | undefined;\n\n// Providing a type that maps models\n// into a schema using lists and controls\nexport type FormSchema<T> = [T] extends [Primitive]\n ? Control<T>\n : T extends Array<infer U>\n ? ControlList<U>\n : { [K in keyof T]: FormSchema<T[K]> };\n\nexport const createFormSchema = <T>(value: T): FormSchema<T> => {\n // Lists are parsed out\n if (Array.isArray(value)) {\n return controlList(value) as FormSchema<T>;\n }\n\n // Objects are converted to a nested tree\n if (value !== null && typeof value === 'object' && !(value instanceof Date)) {\n const groupEntries = Object.entries(value).map(([key, val]) => {\n return [key, createFormSchema(val)];\n });\n return Object.fromEntries(groupEntries) as FormSchema<T>;\n }\n\n // C) It is a Primitive -> Create a Leaf Control\n // We wrap the raw value in a grain to make it reactive\n return control(value) as FormSchema<T>;\n};\n","import type { FormSchema } from './form-schema';\n\nexport const setFormValue = <T>(schema: FormSchema<T>, model: T) => {\n // If we reached a leaf or a single control, we simply\n // set the value.\n if ('isControl' in schema) {\n schema.value.set(model);\n }\n\n // Lists have their own setter fn\n if ('isControlList' in schema && Array.isArray(model)) {\n schema.set(model);\n }\n\n if (typeof model === 'object' && model !== null) {\n for (const [key, value] of Object.entries(model)) {\n if (key in schema) {\n //@ts-expect-error Typescript unable to correctly nest the type here\n setFormValue(schema[key], value);\n }\n }\n }\n};\n","import type { Control } from './control';\nimport type { FormSchema } from './form-schema';\n\nexport const iterateSchema = <T>(schema: FormSchema<T>, run: (control: Control) => void) => {\n // If just control, run callback\n if ('isControl' in schema) {\n return run(schema as Control);\n }\n\n // Lists are deeply iterated\n if ('isControlList' in schema) {\n for (const control of schema.controls()) {\n iterateSchema(control, run);\n }\n return;\n }\n\n for (const value of Object.values(schema)) {\n iterateSchema(value, run);\n }\n};\n","import type { FormSchema } from './form-schema';\nimport { iterateSchema } from './iterate-schema';\n\nexport const touchAll = <T>(controls: FormSchema<T>) => {\n iterateSchema(controls, (control) => control.touched.set(true));\n};\n","import { type Grain, combined, derived } from '@grainular/grains';\nimport { deriveSchemaErrors } from './derive-schema-errors';\nimport { deriveSchemaTouched } from './derive-schema-touched';\nimport { deriveSchemaValue } from './derive-schema-value';\nimport { type FormSchema, createFormSchema } from './form-schema';\nimport { setFormValue } from './handle-form-value';\nimport { iterateSchema } from './iterate-schema';\nimport { touchAll } from './touch-all';\n\nexport type Form<T> = {\n value: Grain<T>;\n controls: FormSchema<T>;\n errors: Grain<string[]>;\n isValid: Grain<boolean>;\n isTouched: Grain<boolean>;\n validate: () => boolean;\n set: (value: T) => void;\n reset: () => void;\n};\n\n/**\n *\n * @param model\n * @param schema\n */\nexport const form = <T extends Record<PropertyKey, unknown>>(\n model: T,\n schema: (state: FormSchema<T>) => void = () => {},\n): Form<T> => {\n const controls = createFormSchema(model);\n const value = deriveSchemaValue(controls);\n const errors = deriveSchemaErrors(controls);\n const isValid = derived(errors, (errors) => errors.length === 0);\n\n // Touch states\n const touchStates = deriveSchemaTouched(controls);\n const isTouched = derived(touchStates, (states) => states.some(Boolean));\n\n // Create the form setter and reset fn\n const set = (value: T) => setFormValue(controls, value);\n const reset = () => iterateSchema(controls, (control) => control.reset());\n const validate = () => {\n touchAll(controls);\n schema(controls);\n return errors().length === 0;\n };\n\n // Track value changes and run the schema fn\n // whenever the value changes and once on creation\n schema(controls);\n combined([value, touchStates]).subscribe(() => schema(controls));\n\n // Return the created form object\n return { controls, value, errors, isValid, isTouched, set, reset, validate };\n};\n","import { type Grain, combined, derived } from '@grainular/grains';\nimport { $if, type ComponentFragment } from '@grainular/nord';\nimport type { Control } from '../lib/control';\n\ntype ErrorRenderer = (errors: Grain<string>) => ComponentFragment;\ntype ControlErrorOptions = {\n showOn?: 'touched' | 'always';\n};\n\nexport const $controlErrors = <V>(\n control: Control<V>,\n renderer: ErrorRenderer,\n options: ControlErrorOptions = { showOn: 'touched' },\n) => {\n // We create a derived state that only emits errors when the conditions are met.\n // Otherwise, it emits null, which causes $if to unmount the view.\n const visibleErrors = derived(combined([control.errors, control.touched]), ([errors, touched]) => {\n // 1. If there are no errors, render nothing\n if (!errors || errors.length === 0) {\n return null;\n }\n\n // 2. Check visibility conditions\n const shouldShow = options.showOn === 'always' || touched;\n\n // 3. Return errors if visible, otherwise null\n return shouldShow ? errors : null;\n });\n\n // Delegate to the existing $if structural directive\n return $if(derived(visibleErrors, (value) => (value ?? []).length > 0)).$then(() =>\n renderer(derived(visibleErrors, (errors) => (errors ?? []).join(', '))),\n );\n};\n","import type { WritableGrain } from '@grainular/grains';\n\ntype HasError = { errors: WritableGrain<string[]> };\nexport const setControlError = (control: HasError, message: string) => {\n control.errors.update((errors) => {\n return [...new Set([...(errors ?? []), message])];\n });\n};\n\nexport const clearControlError = (control: HasError, message: string) => {\n control.errors.update((errors) => {\n return [...new Set([...(errors ?? []).filter((msg) => msg !== message)])];\n });\n};\n","import type { Control } from '../lib/control';\nimport { clearControlError, setControlError } from './core';\n\ntype ValidatorData<T> = T & { message: string };\ntype ValidatorFn<Opts, T> = (\n control: Control<T>,\n setError: () => void,\n clearError: () => void,\n opts: Omit<ValidatorData<Opts>, 'message'>,\n) => void;\n\n// We need to provide this type explicitly to\n// avoid invariance problems. Sucks but that's\n// the price to pay for type safe validators.\nexport type Validator<Opts, T> = <V extends T>(control: Control<V>, opts: ValidatorData<Opts>) => void;\n\nexport const createValidator = <Opts extends Record<PropertyKey, unknown>, T>(\n validatorFn: ValidatorFn<Opts, T>,\n): Validator<Opts, T> => {\n return <V extends T>(control: Control<V>, { message, ...opts }: ValidatorData<Opts>) => {\n // Casting the control makes it work. This should\n // be fine, as we only ever read the value of the\n // control.\n const castControl = control as unknown as Control<T>;\n\n const setError = () => setControlError(castControl, message);\n const clearError = () => clearControlError(castControl, message);\n if (control.touched()) {\n validatorFn(castControl, setError, clearError, opts);\n }\n };\n};\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nconst EMAIL_REGEX =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n\nexport const email: Validator<Record<string, never>, string | null> = createValidator(\n (control: Control<string | null>, setError, clearError) => {\n const value = control.value();\n\n // Empty values are valid (handled by 'required')\n if (value === null || value === '') {\n return clearError();\n }\n\n EMAIL_REGEX.test(value) ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const max: Validator<{ max: number }, number | null> = createValidator(\n (control: Control<number | null>, setError, clearError, { max }) => {\n const value = control.value();\n\n if (value === null || typeof value !== 'number') return clearError();\n value <= max ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { createValidator, type Validator } from './create-validator';\n\nexport const maxLength: Validator<{ max: number }, unknown[]> = createValidator(\n (control: Control<unknown[]>, setError, clearError, { max }) => {\n const value = control.value();\n\n if (!Array.isArray(value) || (Array.isArray(value) && value.length <= max)) return clearError();\n value.length > max && setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const min: Validator<{ min: number }, number | null> = createValidator(\n (control: Control<number | null>, setError, clearError, { min }) => {\n const value = control.value();\n\n if (value === null || typeof value !== 'number') return clearError();\n value >= min ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { createValidator, type Validator } from './create-validator';\n\nexport const minLength: Validator<{ min: number }, unknown[]> = createValidator(\n (control: Control<unknown[]>, setError, clearError, { min }) => {\n const value = control.value();\n\n if (!Array.isArray(value) || (Array.isArray(value) && value.length >= min)) return clearError();\n value.length < min && setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const pattern: Validator<{ regex: RegExp }, string | null> = createValidator(\n (control: Control<string | null>, setError, clearError, { regex }) => {\n const value = control.value();\n\n // If the value is empty/null, we clear the error.\n // We leave emptiness checks to the 'required' validator.\n if (value === null || value === '') {\n return clearError();\n }\n\n // Test the regex against the value\n regex.test(value) ? clearError() : setError();\n },\n);\n","import { createValidator } from './create-validator';\n\nexport const required = createValidator((control, setError, clearError) => {\n const value = control.value();\n\n if (typeof value !== 'string') {\n return value ? clearError() : setError();\n }\n\n value.trim() !== '' ? clearError() : setError();\n});\n","import type { ControlList } from '../lib/control-list';\nimport type { FormSchema } from '../lib/form-schema';\n\nexport const validateEach = <T>(control: ControlList<T>, schemaFn: (schema: FormSchema<T>, idx: number) => void) => {\n control.controls().forEach((control, idx) => schemaFn(control, idx));\n};\n"]}
@@ -0,0 +1,3 @@
1
+ var{defineProperty:m,getOwnPropertyNames:V,getOwnPropertyDescriptor:b}=Object,q=Object.prototype.hasOwnProperty;function s(r){return this[r]}var v=(r)=>{var o=(p??=new WeakMap).get(r),t;if(o)return o;if(o=m({},"__esModule",{value:!0}),r&&typeof r==="object"||typeof r==="function"){for(var e of V(r))if(!q.call(o,e))m(o,e,{get:s.bind(r,e),enumerable:!(t=b(r,e))||t.enumerable})}return p.set(r,o),o},p;var A=(r)=>r;function C(r,o){this[r]=A.bind(null,o)}var F=(r,o)=>{for(var t in o)m(r,t,{get:o[t],enumerable:!0,configurable:!0,set:C.bind(o,t)})};var $={};F($,{validateEach:()=>L.validateEach,touchAll:()=>l.touchAll,required:()=>E.required,pattern:()=>u.pattern,minLength:()=>g.minLength,min:()=>y.min,maxLength:()=>h.maxLength,max:()=>d.max,form:()=>a.form,email:()=>c.email,createValidator:()=>i.createValidator,control:()=>f.control,bind:()=>x.bind,$controlErrors:()=>n.$controlErrors});module.exports=v($);
2
+
3
+ //# debugId=FABFD12816BEAD5C64756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "FABFD12816BEAD5C64756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1,2 @@
1
+ import {createDirective,$if}from'@grainular/nord';import {grain,derived,combined,readonly,flattened}from'@grainular/grains';var M=new Map([[t=>t instanceof HTMLInputElement&&t.type==="checkbox",t=>{let r=t;return {get:()=>r.checked,set:e=>{r.checked=!!e;}}}],[t=>t instanceof HTMLInputElement&&t.type==="radio",t=>{let r=t;return {get:()=>r.value,set:e=>{r.checked=e===r.value;}}}],[t=>t instanceof HTMLInputElement&&t.type==="file",t=>{let r=t;return {get:()=>r.files,set:()=>{}}}],[t=>t instanceof HTMLSelectElement&&t.type==="select-multiple",t=>{let r=t;return {get:()=>Array.from(r.selectedOptions,e=>e.value),set:e=>{queueMicrotask(()=>{let o=Array.isArray(e)?e:[e];for(let n of r.options)n.selected=o.includes(n.value);});}}}],[t=>t instanceof HTMLSelectElement,t=>{let r=t;return {get:()=>Array.from(r.selectedOptions,e=>e.value).at(0),set:e=>{queueMicrotask(()=>{for(let o of r.options)o.selected=e===o.value;});}}}],[t=>t instanceof HTMLInputElement&&(t.type==="number"||t.type==="range"),t=>{let r=t;return {get:()=>r.value===""?null:r.valueAsNumber,set:e=>{r.value=String(e??"");}}}],[t=>t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement,t=>{let r=t;return {get:()=>r.value,set:e=>{r.value=String(e??"");}}}]]),b=t=>{for(let[r,e]of M)if(r(t))return e(t);return {get:()=>null,set:()=>{}}};var B=(t,r="input")=>createDirective(e=>{let{get:o,set:n}=b(e);n(t());let i=t.subscribe(l=>n(l)),a=()=>t.set(o());return e.addEventListener(r,a),()=>{e.removeEventListener(r,a),i();}});var I=(t,r)=>(r()?t.setAttribute("disabled",""):t.removeAttribute("disabled"),r.subscribe(e=>{e?t.setAttribute("disabled",""):t.removeAttribute("disabled");})),j=(t,r,e,o)=>{let n=i=>{i.type==="focus"&&e(),i.type==="blur"&&(r(),o());};return t.addEventListener("focus",n),t.addEventListener("blur",n),()=>{t.removeEventListener("focus",n),t.removeEventListener("blur",n);}},R=(t,r,e,o)=>{let{get:n,set:i}=b(t);i(r());let a=()=>r.set(n());t.addEventListener(e,a);let l=r.subscribe(c=>{o(),i(c);});return ()=>{t.removeEventListener(e,a),l();}},z=({updateOn:t},r,e,o,n,i,a)=>createDirective(l=>{let c=I(l,i),y=j(l,r,e,n),m=R(l,a,t,o);return ()=>{c(),y(),m();}}),C=t=>{let r=grain(t),e=grain([]),o=grain(false),n=derived(e,m=>m.length===0),i=grain(false),a=grain(false),l=grain(false),c=()=>{e.set([]),i.set(false),a.set(false),l.set(false),r.set(t);},y=m=>z(m,()=>i.set(true),()=>a.set(true),()=>l.set(true),()=>a.set(false),o,r);return {id:crypto.randomUUID(),isControl:true,value:r,errors:e,disabled:o,isValid:n,touched:i,focused:a,dirty:l,reset:c,bind:(m={})=>y({updateOn:"input",...m})}};var T=t=>"isControl"in t?derived(t.errors,r=>r):"isControlList"in t?flattened(derived(t.controls,r=>{let e=r.map(o=>T(o));return derived(combined(e),o=>o.flat())})):derived(combined(Object.values(t).map(r=>T(r))),r=>r.flat());var g=t=>"isControl"in t?derived(t.touched,r=>[r]):"isControlList"in t?flattened(derived(t.controls,r=>r.map(e=>g(e)))):derived(combined(Object.values(t).map(r=>g(r))),r=>r.flat());var h=t=>{if("isControl"in t)return readonly(t.value);if("isControlList"in t)return flattened(derived(t.controls,e=>combined(e.map(h))));let r=Object.entries(t).map(([e,o])=>({key:e,grain:h(o)}));return derived(combined(r.map(e=>e.grain)),e=>e.reduce((o,n,i)=>{let a=r[i].key;return o[a]=n,o},{}))};var A=t=>{let r=t.map(o=>u(o)),e=grain(r);return {isControlList:true,controls:e,add:o=>{let n=u(o);e.update(i=>[...i,n]);},remove:o=>{e.update(n=>[...n.filter(i=>i!==o)]);},at:o=>e()[o],set:o=>{let n=o.map(i=>u(i));e.set(n);},reset:()=>{e.set(r);}}};var u=t=>{if(Array.isArray(t))return A(t);if(t!==null&&typeof t=="object"&&!(t instanceof Date)){let r=Object.entries(t).map(([e,o])=>[e,u(o)]);return Object.fromEntries(r)}return C(t)};var V=(t,r)=>{if("isControl"in t&&t.value.set(r),"isControlList"in t&&Array.isArray(r)&&t.set(r),typeof r=="object"&&r!==null)for(let[e,o]of Object.entries(r))e in t&&V(t[e],o);};var f=(t,r)=>{if("isControl"in t)return r(t);if("isControlList"in t){for(let e of t.controls())f(e,r);return}for(let e of Object.values(t))f(e,r);};var S=t=>{f(t,r=>r.touched.set(true));};var _=(t,r=()=>{})=>{let e=u(t),o=h(e),n=T(e),i=derived(n,p=>p.length===0),a=g(e),l=derived(a,p=>p.some(Boolean)),c=p=>V(e,p),y=()=>f(e,p=>p.reset()),m=()=>(S(e),r(e),n().length===0);return r(e),combined([o,a]).subscribe(()=>r(e)),{controls:e,value:o,errors:n,isValid:i,isTouched:l,set:c,reset:y,validate:m}};var Q=(t,r,e={showOn:"touched"})=>{let o=derived(combined([t.errors,t.touched]),([n,i])=>!n||n.length===0?null:e.showOn==="always"||i?n:null);return $if(derived(o,n=>(n??[]).length>0)).$then(()=>r(derived(o,n=>(n??[]).join(", "))))};var k=(t,r)=>{t.errors.update(e=>[...new Set([...e??[],r])]);},w=(t,r)=>{t.errors.update(e=>[...new Set([...(e??[]).filter(o=>o!==r)])]);};var s=t=>(r,{message:e,...o})=>{let n=r,i=()=>k(n,e),a=()=>w(n,e);r.touched()&&t(n,i,a,o);};var Y=/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,tt=s((t,r,e)=>{let o=t.value();if(o===null||o==="")return e();Y.test(o)?e():r();});var rt=s((t,r,e,{max:o})=>{let n=t.value();if(n===null||typeof n!="number")return e();n<=o?e():r();});var et=s((t,r,e,{max:o})=>{let n=t.value();if(!Array.isArray(n)||Array.isArray(n)&&n.length<=o)return e();n.length>o&&r();});var ot=s((t,r,e,{min:o})=>{let n=t.value();if(n===null||typeof n!="number")return e();n>=o?e():r();});var nt=s((t,r,e,{min:o})=>{let n=t.value();if(!Array.isArray(n)||Array.isArray(n)&&n.length>=o)return e();n.length<o&&r();});var it=s((t,r,e,{regex:o})=>{let n=t.value();if(n===null||n==="")return e();o.test(n)?e():r();});var at=s((t,r,e)=>{let o=t.value();if(typeof o!="string")return o?e():r();o.trim()!==""?e():r();});var st=(t,r)=>{t.controls().forEach((e,o)=>r(e,o));};export{Q as $controlErrors,B as bind,C as control,s as createValidator,tt as email,_ as form,rt as max,et as maxLength,ot as min,nt as minLength,it as pattern,at as required,S as touchAll,st as validateEach};//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/value-binding.ts","../../src/directives/bind.directive.ts","../../src/lib/control.ts","../../src/lib/derive-schema-errors.ts","../../src/lib/derive-schema-touched.ts","../../src/lib/derive-schema-value.ts","../../src/lib/control-list.ts","../../src/lib/form-schema.ts","../../src/lib/handle-form-value.ts","../../src/lib/iterate-schema.ts","../../src/lib/touch-all.ts","../../src/lib/form.ts","../../src/structs/control-errors.struct.ts","../../src/validators/core.ts","../../src/validators/create-validator.ts","../../src/validators/email.ts","../../src/validators/max.ts","../../src/validators/max-length.ts","../../src/validators/min.ts","../../src/validators/min-length.ts","../../src/validators/pattern.ts","../../src/validators/required.ts","../../src/validators/validate-each.ts"],"names":["bindings","node","input","val","select","opt","values","option","getBinding","predicate","factory","bind","value","event","createDirective","get","set","cleanup","handler","handleNodeDisabledState","disabled","state","handleNodeFocusState","setTouched","setFocused","blur","handleNodeValueBinding","setDirty","createControlBinding","resolveDisabledState","resolveFocusState","resolveValueBinding","control","initialValue","grain","errors","isValid","derived","touched","focused","dirty","reset","binding","options","deriveSchemaErrors","schema","flattened","schemas","errorGrains","s","combined","nested","subSchema","deriveSchemaTouched","deriveSchemaValue","readonly","keyedValues","key","entry","acc","index","controlList","initialValues","initialSchemas","v","createFormSchema","controls","current","c","idx","updatedSchema","groupEntries","setFormValue","model","iterateSchema","run","touchAll","form","touchStates","isTouched","states","validate","$controlErrors","renderer","visibleErrors","$if","setControlError","message","clearControlError","msg","createValidator","validatorFn","opts","castControl","setError","clearError","EMAIL_REGEX","email","max","maxLength","min","minLength","pattern","regex","required","validateEach","schemaFn"],"mappings":"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","file":"index.js","sourcesContent":["// --- Interfaces ---\ntype Binding = {\n get: () => unknown;\n set: (value: unknown) => void;\n};\n\ntype Predicate = (node: Element) => boolean;\ntype Factory = (node: Element) => Binding;\n\n// --- The Dictionary ---\nconst bindings = new Map<Predicate, Factory>([\n // 1. Checkbox\n [\n (node) => node instanceof HTMLInputElement && node.type === 'checkbox',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.checked,\n set: (val) => {\n input.checked = Boolean(val);\n },\n };\n },\n ],\n // 1.5 -> Radio\n [\n (node) => node instanceof HTMLInputElement && node.type === 'radio',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.value,\n set: (val) => {\n input.checked = val === input.value;\n },\n };\n },\n ],\n // 2. File Input (Read-Only)\n [\n (node) => node instanceof HTMLInputElement && node.type === 'file',\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => input.files,\n set: () => {\n /* No-op: File inputs are security locked */\n },\n };\n },\n ],\n // 3. Multi-Select\n [\n (node) => node instanceof HTMLSelectElement && node.type === 'select-multiple',\n (node) => {\n const select = node as HTMLSelectElement;\n return {\n get: () => Array.from(select.selectedOptions, (opt) => opt.value),\n set: (val) => {\n queueMicrotask(() => {\n const values = Array.isArray(val) ? val : [val];\n for (const option of select.options) {\n option.selected = values.includes(option.value);\n }\n });\n },\n };\n },\n ],\n // 3.5 -> Single Select\n [\n (node) => node instanceof HTMLSelectElement,\n (node) => {\n const select = node as HTMLSelectElement;\n return {\n get: () => Array.from(select.selectedOptions, (opt) => opt.value).at(0),\n set: (val) => {\n queueMicrotask(() => {\n for (const option of select.options) {\n option.selected = val === option.value;\n }\n });\n },\n };\n },\n ],\n // 4. Numeric Inputs (Number & Range)\n [\n (node) => node instanceof HTMLInputElement && (node.type === 'number' || node.type === 'range'),\n (node) => {\n const input = node as HTMLInputElement;\n return {\n get: () => (input.value === '' ? null : input.valueAsNumber),\n set: (val) => {\n input.value = String(val ?? '');\n },\n };\n },\n ],\n // 5. Default Fallback (Text, Textarea, Single Select, etc.)\n [\n (node) => node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement,\n (node) => {\n // Safe to cast to generic input interface usually, or just use 'value' property\n const input = node as HTMLInputElement;\n return {\n get: () => input.value,\n set: (val) => {\n input.value = String(val ?? '');\n },\n };\n },\n ],\n]);\n\nexport const getBinding = (node: Element): Binding => {\n for (const [predicate, factory] of bindings) {\n if (predicate(node)) return factory(node);\n }\n // Fallback for non-form elements (or throw error)\n return { get: () => null, set: () => {} };\n};\n","import type { WritableGrain } from '@grainular/grains';\nimport { createDirective } from '@grainular/nord';\nimport { getBinding } from '../lib/value-binding';\n\nexport const bind = <V>(value: WritableGrain<V>, event: 'change' | 'input' | 'blur' = 'input') => {\n return createDirective((node) => {\n const { get, set } = getBinding(node);\n\n // Setter logic\n set(value());\n const cleanup = value.subscribe((value) => set(value));\n\n // Handler logic\n const handler = () => value.set(get() as V);\n node.addEventListener(event, handler);\n\n return () => {\n node.removeEventListener(event, handler);\n cleanup();\n };\n });\n};\n","import { type Grain, type WritableGrain, derived, grain } from '@grainular/grains';\nimport { createDirective } from '@grainular/nord';\nimport { getBinding } from './value-binding';\n\ntype ControlBindingOptions = {\n updateOn?: 'change' | 'input' | 'blur';\n};\n\nexport type Control<V = unknown> = {\n isControl: true;\n id: string;\n\n // Writable state\n value: WritableGrain<V>;\n errors: WritableGrain<string[]>;\n disabled: WritableGrain<boolean>;\n\n // Derived / event state\n isValid: Grain<boolean>;\n focused: WritableGrain<boolean>;\n touched: WritableGrain<boolean>;\n dirty: WritableGrain<boolean>;\n\n // Resets the value\n reset: () => void;\n\n // The directive used to bind\n // to the input element, using\n // a event\n bind: (options?: ControlBindingOptions) => ReturnType<typeof createDirective>;\n};\n\nconst handleNodeDisabledState = (node: Element, disabled: Grain<boolean>) => {\n disabled() ? node.setAttribute('disabled', '') : node.removeAttribute('disabled');\n\n return disabled.subscribe((state) => {\n state ? node.setAttribute('disabled', '') : node.removeAttribute('disabled');\n });\n};\n\nconst handleNodeFocusState = (node: Element, setTouched: () => void, setFocused: () => void, blur: () => void) => {\n const handler = (event: Event) => {\n if (event.type === 'focus') {\n setFocused();\n }\n\n if (event.type === 'blur') {\n setTouched();\n blur();\n }\n };\n\n node.addEventListener('focus', handler);\n node.addEventListener('blur', handler);\n\n return () => {\n node.removeEventListener('focus', handler);\n node.removeEventListener('blur', handler);\n };\n};\n\nconst handleNodeValueBinding = <V>(node: Element, value: WritableGrain<V>, event: string, setDirty: () => void) => {\n const { get, set } = getBinding(node);\n set(value());\n\n const handler = () => value.set(get() as V);\n node.addEventListener(event, handler);\n\n const cleanup = value.subscribe((value) => {\n setDirty();\n set(value);\n });\n\n return () => {\n node.removeEventListener(event, handler);\n cleanup();\n };\n};\n\n// Function to set up the control binding\n// to the control node. This is will be a\nconst createControlBinding = <V>(\n { updateOn: event }: Required<ControlBindingOptions>,\n setTouched: () => void,\n setFocused: () => void,\n setDirty: () => void,\n blur: () => void,\n disabled: Grain<boolean>,\n value: WritableGrain<V>,\n) => {\n return createDirective((node) => {\n // The bindings between the node and the state\n // needs to track multiple different states and\n // attributes.\n const resolveDisabledState = handleNodeDisabledState(node, disabled);\n const resolveFocusState = handleNodeFocusState(node, setTouched, setFocused, blur);\n const resolveValueBinding = handleNodeValueBinding(node, value, event, setDirty);\n\n return () => {\n resolveDisabledState();\n resolveFocusState();\n resolveValueBinding();\n };\n });\n};\n\n/**\n * Method to create a reactive control with\n * methods to retrieve the value and create\n * a binding\n * @param value\n */\nexport const control = <V>(initialValue: V): Control<V> => {\n const value = grain(initialValue);\n const errors = grain<string[]>([]);\n const disabled = grain(false);\n\n const isValid = derived(errors, (errors) => errors.length === 0);\n const touched = grain(false);\n const focused = grain(false);\n const dirty = grain(false);\n\n const reset = () => {\n errors.set([]);\n touched.set(false);\n focused.set(false);\n dirty.set(false);\n value.set(initialValue);\n };\n\n const binding = (options: Required<ControlBindingOptions>) => {\n return createControlBinding<V>(\n options,\n () => touched.set(true),\n () => focused.set(true),\n () => dirty.set(true),\n () => focused.set(false),\n disabled,\n value,\n );\n };\n\n return {\n id: crypto.randomUUID(),\n isControl: true,\n value,\n errors,\n disabled,\n isValid,\n touched,\n focused,\n dirty,\n reset,\n bind: (options: ControlBindingOptions = {}) => {\n return binding({ updateOn: 'input', ...options });\n },\n };\n};\n","import { type Grain, combined, derived, flattened } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaErrors = <T>(schema: FormSchema<T>): Grain<string[]> => {\n // Normalize the nullable errors state\n if ('isControl' in schema) {\n return derived(schema.errors, (errors) => errors);\n }\n\n // Lists are deeply flattened and normalized\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n const errorGrains = schemas.map((s) => deriveSchemaErrors(s));\n return derived(combined(errorGrains), (nested) => nested.flat());\n }),\n );\n }\n\n // Anything else is flattened\n return derived(\n combined(\n Object.values(schema).map((subSchema) => {\n return deriveSchemaErrors(subSchema);\n }),\n ),\n (nested) => nested.flat(),\n );\n};\n","import { type Grain, combined, derived, flattened } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaTouched = <T>(schema: FormSchema<T>): Grain<boolean[]> => {\n // Normalize the nullable errors state\n if ('isControl' in schema) {\n return derived(schema.touched, (errors) => [errors]);\n }\n\n // Lists are deeply flattened and normalized\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n return schemas.map((s) => deriveSchemaTouched(s));\n }),\n );\n }\n\n // Anything else is flattened\n return derived(\n combined(\n Object.values(schema).map((subSchema) => {\n return deriveSchemaTouched(subSchema);\n }),\n ),\n (nested) => nested.flat(),\n );\n};\n","import { type Grain, combined, derived, flattened, readonly } from '@grainular/grains';\nimport type { FormSchema } from './form-schema';\n\nexport const deriveSchemaValue = <T>(schema: FormSchema<T>): Grain<T> => {\n // Handle pure controls by returning the\n // direct control value\n if ('isControl' in schema) return readonly(schema.value);\n\n // We check for the 'controls' grain and array methods\n if ('isControlList' in schema) {\n return flattened(\n derived(schema.controls, (schemas) => {\n return combined(schemas.map(deriveSchemaValue));\n }),\n );\n }\n\n // Get all the child value grains\n const keyedValues = Object.entries(schema).map(([key, subSchema]) => {\n return { key, grain: deriveSchemaValue(subSchema) };\n });\n\n // Extract just the grains for 'combined'\n return derived(combined(keyedValues.map((entry) => entry.grain)), (values) => {\n // Reconstruct the object using the original keys and the new values\n return values.reduce((acc, val, index) => {\n const key = keyedValues[index].key;\n // @ts-expect-error\n acc[key] = val;\n return acc;\n }, {} as T);\n }) as Grain<T>;\n};\n","import { type WritableGrain, grain } from '@grainular/grains';\nimport { type FormSchema, createFormSchema } from './form-schema';\n\nexport type ControlList<T> = {\n isControlList: true;\n controls: WritableGrain<FormSchema<T>[]>;\n add: (value: T) => void;\n remove: (control: FormSchema<T>) => void;\n at: (idx: number) => FormSchema<T> | undefined;\n\n reset: () => void;\n set: (value: T[]) => void;\n};\n\nexport const controlList = <T>(initialValues: T[]): ControlList<T> => {\n const initialSchemas = initialValues.map((v) => createFormSchema(v));\n const controls = grain(initialSchemas);\n\n return {\n isControlList: true,\n controls,\n\n // Add: Create the schema for the new value and push it to the state\n add: (value: T) => {\n const schema = createFormSchema(value);\n controls.update((current) => [...current, schema]);\n },\n\n // Remove: Filter the array by comparator\n remove: (control: FormSchema<T>) => {\n controls.update((current) => {\n return [...current.filter((c) => c !== control)];\n });\n },\n\n // At: Access the reactive schema at a specific index\n // (Note: This returns the SCHEMA, so you can do .at(0).value() or .at(0).bind())\n at: (idx: number) => {\n return controls()[idx];\n },\n\n set: (value: T[]) => {\n // No reconciliation here, as we never know how the values\n // passed actually relate. Better to just overwrite completely\n const updatedSchema = value.map((value) => createFormSchema(value));\n controls.set(updatedSchema);\n },\n\n // Reset's the control to it's\n // initial value\n reset: () => {\n controls.set(initialSchemas);\n },\n };\n};\n","import { type Control, control } from './control';\nimport { type ControlList, controlList } from './control-list';\n\n// Helper to stop recursion on simple types (including Date)\ntype Primitive = string | number | boolean | Date | null | undefined;\n\n// Providing a type that maps models\n// into a schema using lists and controls\nexport type FormSchema<T> = [T] extends [Primitive]\n ? Control<T>\n : T extends Array<infer U>\n ? ControlList<U>\n : { [K in keyof T]: FormSchema<T[K]> };\n\nexport const createFormSchema = <T>(value: T): FormSchema<T> => {\n // Lists are parsed out\n if (Array.isArray(value)) {\n return controlList(value) as FormSchema<T>;\n }\n\n // Objects are converted to a nested tree\n if (value !== null && typeof value === 'object' && !(value instanceof Date)) {\n const groupEntries = Object.entries(value).map(([key, val]) => {\n return [key, createFormSchema(val)];\n });\n return Object.fromEntries(groupEntries) as FormSchema<T>;\n }\n\n // C) It is a Primitive -> Create a Leaf Control\n // We wrap the raw value in a grain to make it reactive\n return control(value) as FormSchema<T>;\n};\n","import type { FormSchema } from './form-schema';\n\nexport const setFormValue = <T>(schema: FormSchema<T>, model: T) => {\n // If we reached a leaf or a single control, we simply\n // set the value.\n if ('isControl' in schema) {\n schema.value.set(model);\n }\n\n // Lists have their own setter fn\n if ('isControlList' in schema && Array.isArray(model)) {\n schema.set(model);\n }\n\n if (typeof model === 'object' && model !== null) {\n for (const [key, value] of Object.entries(model)) {\n if (key in schema) {\n //@ts-expect-error Typescript unable to correctly nest the type here\n setFormValue(schema[key], value);\n }\n }\n }\n};\n","import type { Control } from './control';\nimport type { FormSchema } from './form-schema';\n\nexport const iterateSchema = <T>(schema: FormSchema<T>, run: (control: Control) => void) => {\n // If just control, run callback\n if ('isControl' in schema) {\n return run(schema as Control);\n }\n\n // Lists are deeply iterated\n if ('isControlList' in schema) {\n for (const control of schema.controls()) {\n iterateSchema(control, run);\n }\n return;\n }\n\n for (const value of Object.values(schema)) {\n iterateSchema(value, run);\n }\n};\n","import type { FormSchema } from './form-schema';\nimport { iterateSchema } from './iterate-schema';\n\nexport const touchAll = <T>(controls: FormSchema<T>) => {\n iterateSchema(controls, (control) => control.touched.set(true));\n};\n","import { type Grain, combined, derived } from '@grainular/grains';\nimport { deriveSchemaErrors } from './derive-schema-errors';\nimport { deriveSchemaTouched } from './derive-schema-touched';\nimport { deriveSchemaValue } from './derive-schema-value';\nimport { type FormSchema, createFormSchema } from './form-schema';\nimport { setFormValue } from './handle-form-value';\nimport { iterateSchema } from './iterate-schema';\nimport { touchAll } from './touch-all';\n\nexport type Form<T> = {\n value: Grain<T>;\n controls: FormSchema<T>;\n errors: Grain<string[]>;\n isValid: Grain<boolean>;\n isTouched: Grain<boolean>;\n validate: () => boolean;\n set: (value: T) => void;\n reset: () => void;\n};\n\n/**\n *\n * @param model\n * @param schema\n */\nexport const form = <T extends Record<PropertyKey, unknown>>(\n model: T,\n schema: (state: FormSchema<T>) => void = () => {},\n): Form<T> => {\n const controls = createFormSchema(model);\n const value = deriveSchemaValue(controls);\n const errors = deriveSchemaErrors(controls);\n const isValid = derived(errors, (errors) => errors.length === 0);\n\n // Touch states\n const touchStates = deriveSchemaTouched(controls);\n const isTouched = derived(touchStates, (states) => states.some(Boolean));\n\n // Create the form setter and reset fn\n const set = (value: T) => setFormValue(controls, value);\n const reset = () => iterateSchema(controls, (control) => control.reset());\n const validate = () => {\n touchAll(controls);\n schema(controls);\n return errors().length === 0;\n };\n\n // Track value changes and run the schema fn\n // whenever the value changes and once on creation\n schema(controls);\n combined([value, touchStates]).subscribe(() => schema(controls));\n\n // Return the created form object\n return { controls, value, errors, isValid, isTouched, set, reset, validate };\n};\n","import { type Grain, combined, derived } from '@grainular/grains';\nimport { $if, type ComponentFragment } from '@grainular/nord';\nimport type { Control } from '../lib/control';\n\ntype ErrorRenderer = (errors: Grain<string>) => ComponentFragment;\ntype ControlErrorOptions = {\n showOn?: 'touched' | 'always';\n};\n\nexport const $controlErrors = <V>(\n control: Control<V>,\n renderer: ErrorRenderer,\n options: ControlErrorOptions = { showOn: 'touched' },\n) => {\n // We create a derived state that only emits errors when the conditions are met.\n // Otherwise, it emits null, which causes $if to unmount the view.\n const visibleErrors = derived(combined([control.errors, control.touched]), ([errors, touched]) => {\n // 1. If there are no errors, render nothing\n if (!errors || errors.length === 0) {\n return null;\n }\n\n // 2. Check visibility conditions\n const shouldShow = options.showOn === 'always' || touched;\n\n // 3. Return errors if visible, otherwise null\n return shouldShow ? errors : null;\n });\n\n // Delegate to the existing $if structural directive\n return $if(derived(visibleErrors, (value) => (value ?? []).length > 0)).$then(() =>\n renderer(derived(visibleErrors, (errors) => (errors ?? []).join(', '))),\n );\n};\n","import type { WritableGrain } from '@grainular/grains';\n\ntype HasError = { errors: WritableGrain<string[]> };\nexport const setControlError = (control: HasError, message: string) => {\n control.errors.update((errors) => {\n return [...new Set([...(errors ?? []), message])];\n });\n};\n\nexport const clearControlError = (control: HasError, message: string) => {\n control.errors.update((errors) => {\n return [...new Set([...(errors ?? []).filter((msg) => msg !== message)])];\n });\n};\n","import type { Control } from '../lib/control';\nimport { clearControlError, setControlError } from './core';\n\ntype ValidatorData<T> = T & { message: string };\ntype ValidatorFn<Opts, T> = (\n control: Control<T>,\n setError: () => void,\n clearError: () => void,\n opts: Omit<ValidatorData<Opts>, 'message'>,\n) => void;\n\n// We need to provide this type explicitly to\n// avoid invariance problems. Sucks but that's\n// the price to pay for type safe validators.\nexport type Validator<Opts, T> = <V extends T>(control: Control<V>, opts: ValidatorData<Opts>) => void;\n\nexport const createValidator = <Opts extends Record<PropertyKey, unknown>, T>(\n validatorFn: ValidatorFn<Opts, T>,\n): Validator<Opts, T> => {\n return <V extends T>(control: Control<V>, { message, ...opts }: ValidatorData<Opts>) => {\n // Casting the control makes it work. This should\n // be fine, as we only ever read the value of the\n // control.\n const castControl = control as unknown as Control<T>;\n\n const setError = () => setControlError(castControl, message);\n const clearError = () => clearControlError(castControl, message);\n if (control.touched()) {\n validatorFn(castControl, setError, clearError, opts);\n }\n };\n};\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nconst EMAIL_REGEX =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n\nexport const email: Validator<Record<string, never>, string | null> = createValidator(\n (control: Control<string | null>, setError, clearError) => {\n const value = control.value();\n\n // Empty values are valid (handled by 'required')\n if (value === null || value === '') {\n return clearError();\n }\n\n EMAIL_REGEX.test(value) ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const max: Validator<{ max: number }, number | null> = createValidator(\n (control: Control<number | null>, setError, clearError, { max }) => {\n const value = control.value();\n\n if (value === null || typeof value !== 'number') return clearError();\n value <= max ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { createValidator, type Validator } from './create-validator';\n\nexport const maxLength: Validator<{ max: number }, unknown[]> = createValidator(\n (control: Control<unknown[]>, setError, clearError, { max }) => {\n const value = control.value();\n\n if (!Array.isArray(value) || (Array.isArray(value) && value.length <= max)) return clearError();\n value.length > max && setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const min: Validator<{ min: number }, number | null> = createValidator(\n (control: Control<number | null>, setError, clearError, { min }) => {\n const value = control.value();\n\n if (value === null || typeof value !== 'number') return clearError();\n value >= min ? clearError() : setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { createValidator, type Validator } from './create-validator';\n\nexport const minLength: Validator<{ min: number }, unknown[]> = createValidator(\n (control: Control<unknown[]>, setError, clearError, { min }) => {\n const value = control.value();\n\n if (!Array.isArray(value) || (Array.isArray(value) && value.length >= min)) return clearError();\n value.length < min && setError();\n },\n);\n","import type { Control } from '../lib/control';\nimport { type Validator, createValidator } from './create-validator';\n\nexport const pattern: Validator<{ regex: RegExp }, string | null> = createValidator(\n (control: Control<string | null>, setError, clearError, { regex }) => {\n const value = control.value();\n\n // If the value is empty/null, we clear the error.\n // We leave emptiness checks to the 'required' validator.\n if (value === null || value === '') {\n return clearError();\n }\n\n // Test the regex against the value\n regex.test(value) ? clearError() : setError();\n },\n);\n","import { createValidator } from './create-validator';\n\nexport const required = createValidator((control, setError, clearError) => {\n const value = control.value();\n\n if (typeof value !== 'string') {\n return value ? clearError() : setError();\n }\n\n value.trim() !== '' ? clearError() : setError();\n});\n","import type { ControlList } from '../lib/control-list';\nimport type { FormSchema } from '../lib/form-schema';\n\nexport const validateEach = <T>(control: ControlList<T>, schemaFn: (schema: FormSchema<T>, idx: number) => void) => {\n control.controls().forEach((control, idx) => schemaFn(control, idx));\n};\n"]}
@@ -0,0 +1,2 @@
1
+ import type { WritableGrain } from '@grainular/grains';
2
+ export declare const bind: <V>(value: WritableGrain<V>, event?: "change" | "input" | "blur") => import("@grainular/nord/dist/types/internals/fragment").Fragment;
@@ -0,0 +1,141 @@
1
+ import { WritableGrain, Grain } from '@grainular/grains';
2
+ import { createDirective, ComponentFragment } from '@grainular/nord';
3
+
4
+ declare const bind: <V>(value: WritableGrain<V>, event?: "change" | "input" | "blur") => {
5
+ readonly fragmentId: ReturnType<() => {
6
+ fragmentId: boolean;
7
+ create: (idx: string) => void;
8
+ get: () => string;
9
+ }>;
10
+ resolve: () => string;
11
+ render: () => string;
12
+ hydrate: (target: Node, def?: {
13
+ binding?: (value: unknown) => void;
14
+ scope?: string;
15
+ }) => void;
16
+ };
17
+
18
+ type ControlBindingOptions = {
19
+ updateOn?: 'change' | 'input' | 'blur';
20
+ };
21
+ type Control<V = unknown> = {
22
+ isControl: true;
23
+ id: string;
24
+ value: WritableGrain<V>;
25
+ errors: WritableGrain<string[]>;
26
+ disabled: WritableGrain<boolean>;
27
+ isValid: Grain<boolean>;
28
+ focused: WritableGrain<boolean>;
29
+ touched: WritableGrain<boolean>;
30
+ dirty: WritableGrain<boolean>;
31
+ reset: () => void;
32
+ bind: (options?: ControlBindingOptions) => ReturnType<typeof createDirective>;
33
+ };
34
+ /**
35
+ * Method to create a reactive control with
36
+ * methods to retrieve the value and create
37
+ * a binding
38
+ * @param value
39
+ */
40
+ declare const control: <V>(initialValue: V) => Control<V>;
41
+
42
+ type ControlList<T> = {
43
+ isControlList: true;
44
+ controls: WritableGrain<FormSchema<T>[]>;
45
+ add: (value: T) => void;
46
+ remove: (control: FormSchema<T>) => void;
47
+ at: (idx: number) => FormSchema<T> | undefined;
48
+ reset: () => void;
49
+ set: (value: T[]) => void;
50
+ };
51
+
52
+ type Primitive = string | number | boolean | Date | null | undefined;
53
+ type FormSchema<T> = [T] extends [Primitive] ? Control<T> : T extends Array<infer U> ? ControlList<U> : {
54
+ [K in keyof T]: FormSchema<T[K]>;
55
+ };
56
+
57
+ type Form<T> = {
58
+ value: Grain<T>;
59
+ controls: FormSchema<T>;
60
+ errors: Grain<string[]>;
61
+ isValid: Grain<boolean>;
62
+ isTouched: Grain<boolean>;
63
+ validate: () => boolean;
64
+ set: (value: T) => void;
65
+ reset: () => void;
66
+ };
67
+ /**
68
+ *
69
+ * @param model
70
+ * @param schema
71
+ */
72
+ declare const form: <T extends Record<PropertyKey, unknown>>(model: T, schema?: (state: FormSchema<T>) => void) => Form<T>;
73
+
74
+ declare const touchAll: <T>(controls: FormSchema<T>) => void;
75
+
76
+ type ErrorRenderer = (errors: Grain<string>) => ComponentFragment;
77
+ type ControlErrorOptions = {
78
+ showOn?: 'touched' | 'always';
79
+ };
80
+ declare const $controlErrors: <V>(control: Control<V>, renderer: ErrorRenderer, options?: ControlErrorOptions) => {
81
+ $else: (show: () => ComponentFragment) => {
82
+ readonly fragmentId: ReturnType<() => {
83
+ fragmentId: boolean;
84
+ create: (idx: string) => void;
85
+ get: () => string;
86
+ }>;
87
+ resolve: () => string;
88
+ render: () => string;
89
+ hydrate: (target: Node, def?: {
90
+ binding?: (value: unknown) => void;
91
+ scope?: string;
92
+ }) => void;
93
+ };
94
+ } & {
95
+ readonly fragmentId: ReturnType<() => {
96
+ fragmentId: boolean;
97
+ create: (idx: string) => void;
98
+ get: () => string;
99
+ }>;
100
+ resolve: () => string;
101
+ render: () => string;
102
+ hydrate: (target: Node, def?: {
103
+ binding?: (value: unknown) => void;
104
+ scope?: string;
105
+ }) => void;
106
+ };
107
+
108
+ type ValidatorData<T> = T & {
109
+ message: string;
110
+ };
111
+ type ValidatorFn<Opts, T> = (control: Control<T>, setError: () => void, clearError: () => void, opts: Omit<ValidatorData<Opts>, 'message'>) => void;
112
+ type Validator<Opts, T> = <V extends T>(control: Control<V>, opts: ValidatorData<Opts>) => void;
113
+ declare const createValidator: <Opts extends Record<PropertyKey, unknown>, T>(validatorFn: ValidatorFn<Opts, T>) => Validator<Opts, T>;
114
+
115
+ declare const email: Validator<Record<string, never>, string | null>;
116
+
117
+ declare const max: Validator<{
118
+ max: number;
119
+ }, number | null>;
120
+
121
+ declare const maxLength: Validator<{
122
+ max: number;
123
+ }, unknown[]>;
124
+
125
+ declare const min: Validator<{
126
+ min: number;
127
+ }, number | null>;
128
+
129
+ declare const minLength: Validator<{
130
+ min: number;
131
+ }, unknown[]>;
132
+
133
+ declare const pattern: Validator<{
134
+ regex: RegExp;
135
+ }, string | null>;
136
+
137
+ declare const required: Validator<Record<PropertyKey, unknown>, unknown>;
138
+
139
+ declare const validateEach: <T>(control: ControlList<T>, schemaFn: (schema: FormSchema<T>, idx: number) => void) => void;
140
+
141
+ export { $controlErrors, type Control, type Form, type Validator, bind, control, createValidator, email, form, max, maxLength, min, minLength, pattern, required, touchAll, validateEach };
@@ -0,0 +1,14 @@
1
+ export { bind } from './directives/bind.directive';
2
+ export { control, type Control } from './lib/control';
3
+ export { form, type Form } from './lib/form';
4
+ export { touchAll } from './lib/touch-all';
5
+ export { $controlErrors } from './structs/control-errors.struct';
6
+ export { createValidator, type Validator } from './validators/create-validator';
7
+ export { email } from './validators/email';
8
+ export { max } from './validators/max';
9
+ export { maxLength } from './validators/max-length';
10
+ export { min } from './validators/min';
11
+ export { minLength } from './validators/min-length';
12
+ export { pattern } from './validators/pattern';
13
+ export { required } from './validators/required';
14
+ export { validateEach } from './validators/validate-each';
@@ -0,0 +1,12 @@
1
+ import { type WritableGrain } from '@grainular/grains';
2
+ import { type FormSchema } from './form-schema';
3
+ export type ControlList<T> = {
4
+ isControlList: true;
5
+ controls: WritableGrain<FormSchema<T>[]>;
6
+ add: (value: T) => void;
7
+ remove: (control: FormSchema<T>) => void;
8
+ at: (idx: number) => FormSchema<T> | undefined;
9
+ reset: () => void;
10
+ set: (value: T[]) => void;
11
+ };
12
+ export declare const controlList: <T>(initialValues: T[]) => ControlList<T>;
@@ -0,0 +1,26 @@
1
+ import { type Grain, type WritableGrain } from '@grainular/grains';
2
+ import { type Fragment } from '@grainular/nord';
3
+ type ControlBindingOptions = {
4
+ updateOn?: 'change' | 'input' | 'blur';
5
+ };
6
+ export type Control<V = unknown> = {
7
+ isControl: true;
8
+ id: string;
9
+ value: WritableGrain<V>;
10
+ errors: WritableGrain<string[]>;
11
+ disabled: WritableGrain<boolean>;
12
+ isValid: Grain<boolean>;
13
+ focused: WritableGrain<boolean>;
14
+ touched: WritableGrain<boolean>;
15
+ dirty: WritableGrain<boolean>;
16
+ reset: () => void;
17
+ bind: (options?: ControlBindingOptions) => Fragment;
18
+ };
19
+ /**
20
+ * Method to create a reactive control with
21
+ * methods to retrieve the value and create
22
+ * a binding
23
+ * @param value
24
+ */
25
+ export declare const control: <V>(initialValue: V) => Control<V>;
26
+ export {};
@@ -0,0 +1,3 @@
1
+ import { type Grain } from '@grainular/grains';
2
+ import type { FormSchema } from './form-schema';
3
+ export declare const deriveSchemaErrors: <T>(schema: FormSchema<T>) => Grain<string[]>;
@@ -0,0 +1,3 @@
1
+ import { type Grain } from '@grainular/grains';
2
+ import type { FormSchema } from './form-schema';
3
+ export declare const deriveSchemaTouched: <T>(schema: FormSchema<T>) => Grain<boolean[]>;
@@ -0,0 +1,3 @@
1
+ import { type Grain } from '@grainular/grains';
2
+ import type { FormSchema } from './form-schema';
3
+ export declare const deriveSchemaValue: <T>(schema: FormSchema<T>) => Grain<T>;
@@ -0,0 +1,8 @@
1
+ import { type Control } from './control';
2
+ import { type ControlList } from './control-list';
3
+ type Primitive = string | number | boolean | Date | null | undefined;
4
+ export type FormSchema<T> = [T] extends [Primitive] ? Control<T> : T extends Array<infer U> ? ControlList<U> : {
5
+ [K in keyof T]: FormSchema<T[K]>;
6
+ };
7
+ export declare const createFormSchema: <T>(value: T) => FormSchema<T>;
8
+ export {};
@@ -0,0 +1,18 @@
1
+ import { type Grain } from '@grainular/grains';
2
+ import { type FormSchema } from './form-schema';
3
+ export type Form<T> = {
4
+ value: Grain<T>;
5
+ controls: FormSchema<T>;
6
+ errors: Grain<string[]>;
7
+ isValid: Grain<boolean>;
8
+ isTouched: Grain<boolean>;
9
+ validate: () => boolean;
10
+ set: (value: T) => void;
11
+ reset: () => void;
12
+ };
13
+ /**
14
+ *
15
+ * @param model
16
+ * @param schema
17
+ */
18
+ export declare const form: <T extends Record<PropertyKey, unknown>>(model: T, schema?: (state: FormSchema<T>) => void) => Form<T>;
@@ -0,0 +1,2 @@
1
+ import type { FormSchema } from './form-schema';
2
+ export declare const setFormValue: <T>(schema: FormSchema<T>, model: T) => void;
@@ -0,0 +1,3 @@
1
+ import type { Control } from './control';
2
+ import type { FormSchema } from './form-schema';
3
+ export declare const iterateSchema: <T>(schema: FormSchema<T>, run: (control: Control) => void) => void;
@@ -0,0 +1,2 @@
1
+ import type { FormSchema } from './form-schema';
2
+ export declare const touchAll: <T>(controls: FormSchema<T>) => void;
@@ -0,0 +1,6 @@
1
+ type Binding = {
2
+ get: () => unknown;
3
+ set: (value: unknown) => void;
4
+ };
5
+ export declare const getBinding: (node: Element) => Binding;
6
+ export {};
@@ -0,0 +1,11 @@
1
+ import { type Grain } from '@grainular/grains';
2
+ import { type ComponentFragment } from '@grainular/nord';
3
+ import type { Control } from '../lib/control';
4
+ type ErrorRenderer = (errors: Grain<string>) => ComponentFragment;
5
+ type ControlErrorOptions = {
6
+ showOn?: 'touched' | 'always';
7
+ };
8
+ export declare const $controlErrors: <V>(control: Control<V>, renderer: ErrorRenderer, options?: ControlErrorOptions) => {
9
+ $else: (show: () => ComponentFragment) => import("@grainular/nord/dist/types/internals/fragment").Fragment;
10
+ } & import("@grainular/nord/dist/types/internals/fragment").Fragment;
11
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { WritableGrain } from '@grainular/grains';
2
+ type HasError = {
3
+ errors: WritableGrain<string[]>;
4
+ };
5
+ export declare const setControlError: (control: HasError, message: string) => void;
6
+ export declare const clearControlError: (control: HasError, message: string) => void;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { Control } from '../lib/control';
2
+ type ValidatorData<T> = T & {
3
+ message: string;
4
+ };
5
+ type ValidatorFn<Opts, T> = (control: Control<T>, setError: () => void, clearError: () => void, opts: Omit<ValidatorData<Opts>, 'message'>) => void;
6
+ export type Validator<Opts, T> = <V extends T>(control: Control<V>, opts: ValidatorData<Opts>) => void;
7
+ export declare const createValidator: <Opts extends Record<PropertyKey, unknown>, T>(validatorFn: ValidatorFn<Opts, T>) => Validator<Opts, T>;
8
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type Validator } from './create-validator';
2
+ export declare const email: Validator<Record<string, never>, string | null>;
@@ -0,0 +1,4 @@
1
+ import { type Validator } from './create-validator';
2
+ export declare const maxLength: Validator<{
3
+ max: number;
4
+ }, unknown[]>;
@@ -0,0 +1,4 @@
1
+ import { type Validator } from './create-validator';
2
+ export declare const max: Validator<{
3
+ max: number;
4
+ }, number | null>;
@@ -0,0 +1,4 @@
1
+ import { type Validator } from './create-validator';
2
+ export declare const minLength: Validator<{
3
+ min: number;
4
+ }, unknown[]>;
@@ -0,0 +1,4 @@
1
+ import { type Validator } from './create-validator';
2
+ export declare const min: Validator<{
3
+ min: number;
4
+ }, number | null>;
@@ -0,0 +1,4 @@
1
+ import { type Validator } from './create-validator';
2
+ export declare const pattern: Validator<{
3
+ regex: RegExp;
4
+ }, string | null>;
@@ -0,0 +1 @@
1
+ export declare const required: import("./create-validator").Validator<Record<PropertyKey, unknown>, unknown>;
@@ -0,0 +1,3 @@
1
+ import type { ControlList } from '../lib/control-list';
2
+ import type { FormSchema } from '../lib/form-schema';
3
+ export declare const validateEach: <T>(control: ControlList<T>, schemaFn: (schema: FormSchema<T>, idx: number) => void) => void;
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@grainular/forms",
3
+ "version": "2.0.0-next.1",
4
+ "type": "module",
5
+ "packageManager": "bun@1.2.7",
6
+ "main": "./dist/cjs/index.js",
7
+ "module": "./dist/esm/index.js",
8
+ "types": "./dist/types/index.d.cts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/types/index.d.cts",
12
+ "import": "./dist/esm/index.js",
13
+ "require": "./dist/cjs/index.js"
14
+ }
15
+ },
16
+ "unpkg": "./dist/browser/index.js",
17
+ "devDependencies": {
18
+ "@repository/builder": "0.0.0",
19
+ "@repository/config": "0.0.0",
20
+ "@types/bun": "latest",
21
+ "tsup": "^8.5.1",
22
+ "typescript": "^6.0.3"
23
+ },
24
+ "scripts": {
25
+ "dev": "bunx tsup --watch",
26
+ "build": "bunx tsup",
27
+ "prepublishOnly": "bunx tsup",
28
+ "test": "bun test --coverage"
29
+ },
30
+ "sideEffects": false,
31
+ "publishConfig": {
32
+ "access": "public",
33
+ "tag": "next"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/grainular/nord.git"
44
+ },
45
+ "peerDependencies": {
46
+ "@grainular/nord": "2.0.0-next.2",
47
+ "@grainular/grains": "2.0.0-next.2"
48
+ }
49
+ }