@livenetworks/ashlar 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/README.md +189 -177
  2. package/js/COMPONENTS.md +55 -49
  3. package/js/index.js +22 -5
  4. package/js/ln-accordion/README.md +186 -137
  5. package/js/ln-accordion/ln-accordion.js +1 -1
  6. package/js/ln-ajax/README.md +73 -4
  7. package/js/ln-ajax/ln-ajax.js +1 -1
  8. package/js/ln-ajax/src/ln-ajax.js +13 -13
  9. package/js/ln-api-connector/README.md +261 -150
  10. package/js/ln-api-connector/ln-api-connector.js +1 -1
  11. package/js/ln-api-connector/src/ln-api-connector.js +368 -265
  12. package/js/ln-api-queue/README.md +219 -0
  13. package/js/ln-api-queue/ln-api-queue.js +1 -0
  14. package/js/ln-api-queue/src/ln-api-queue.js +320 -0
  15. package/js/ln-api-queue/src/queue-storage.js +455 -0
  16. package/js/ln-autoresize/README.md +47 -0
  17. package/js/ln-autoresize/ln-autoresize.js +1 -1
  18. package/js/ln-autosave/README.md +33 -1
  19. package/js/ln-autosave/ln-autosave.js +1 -1
  20. package/js/ln-autosave/src/ln-autosave.js +4 -4
  21. package/js/ln-circular-progress/README.md +27 -13
  22. package/js/ln-circular-progress/ln-circular-progress.js +1 -1
  23. package/js/ln-circular-progress/src/ln-circular-progress.js +18 -5
  24. package/js/ln-confirm/README.md +162 -86
  25. package/js/ln-confirm/_ln-confirm.scss +11 -0
  26. package/js/ln-confirm/ln-confirm.js +1 -1
  27. package/js/ln-confirm/src/ln-confirm.js +77 -41
  28. package/js/ln-core/README.md +896 -0
  29. package/js/ln-core/hash.js +92 -0
  30. package/js/ln-core/helpers.js +337 -8
  31. package/js/ln-core/index.js +4 -2
  32. package/js/ln-core/persist.js +29 -3
  33. package/js/ln-core/positioning.js +1 -35
  34. package/js/ln-core/window-cache.js +213 -0
  35. package/js/ln-couchdb-connector/README.md +177 -156
  36. package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
  37. package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +398 -348
  38. package/js/ln-data-coordinator/README.md +536 -165
  39. package/js/ln-data-coordinator/ln-data-coordinator.js +1 -1
  40. package/js/ln-data-coordinator/src/data-read-policy.js +18 -0
  41. package/js/ln-data-coordinator/src/ln-data-coordinator.js +1042 -249
  42. package/js/ln-data-coordinator/src/mutation-receipts.js +46 -0
  43. package/js/ln-data-store/README.md +241 -94
  44. package/js/ln-data-store/ln-data-store.js +1 -1
  45. package/js/ln-data-store/src/ln-data-store.js +694 -699
  46. package/js/ln-date/README.md +39 -1
  47. package/js/ln-date/ln-date-dev.scss +14 -0
  48. package/js/ln-date/ln-date.js +1 -1
  49. package/js/ln-date/src/ln-date.js +236 -178
  50. package/js/ln-debug/README.md +58 -0
  51. package/js/ln-debug/ln-debug.js +1 -0
  52. package/js/ln-debug/src/ln-debug.js +19 -0
  53. package/js/ln-dropdown/README.md +31 -8
  54. package/js/ln-dropdown/ln-dropdown.js +1 -1
  55. package/js/ln-dropdown/src/ln-dropdown.js +30 -13
  56. package/js/ln-editor/README.md +274 -0
  57. package/js/ln-editor/ln-editor.js +1 -0
  58. package/js/ln-editor/ln-editor.scss +43 -0
  59. package/js/ln-editor/src/ln-editor.js +619 -0
  60. package/js/ln-external-links/README.md +44 -5
  61. package/js/ln-external-links/ln-external-links.js +1 -1
  62. package/js/ln-fill/README.md +199 -0
  63. package/js/ln-fill/ln-fill.js +1 -0
  64. package/js/ln-fill/src/ln-fill.js +87 -0
  65. package/js/ln-filter/README.md +189 -99
  66. package/js/ln-filter/ln-filter-dev.scss +8 -0
  67. package/js/ln-filter/ln-filter.js +1 -1
  68. package/js/ln-filter/src/ln-filter.js +22 -7
  69. package/js/ln-form/README.md +212 -49
  70. package/js/ln-form/ln-form.js +1 -1
  71. package/js/ln-form/src/ln-form.js +99 -199
  72. package/js/ln-http/README.md +125 -89
  73. package/js/ln-http/ln-http.js +1 -1
  74. package/js/ln-http/src/ln-http.js +32 -13
  75. package/js/ln-icon/README.md +130 -0
  76. package/js/ln-icon/ln-icon.js +1 -0
  77. package/js/{ln-icons/src/ln-icons.js → ln-icon/src/ln-icon.js} +20 -15
  78. package/js/ln-link/README.md +47 -9
  79. package/js/ln-link/ln-link.js +1 -1
  80. package/js/ln-link/src/ln-link.js +22 -6
  81. package/js/ln-list/README.md +129 -0
  82. package/js/ln-list/ln-list.js +1 -0
  83. package/js/ln-list/ln-list.scss +28 -0
  84. package/js/ln-list/src/ln-list.js +1216 -0
  85. package/js/ln-modal/README.md +185 -154
  86. package/js/ln-modal/ln-modal-dev.scss +13 -0
  87. package/js/ln-modal/ln-modal.js +1 -1
  88. package/js/ln-modal/ln-modal.scss +28 -4
  89. package/js/ln-modal/src/ln-modal.js +137 -201
  90. package/js/ln-modal-coordinator/README.md +99 -0
  91. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +8 -0
  92. package/js/ln-modal-coordinator/ln-modal-coordinator.js +1 -0
  93. package/js/ln-modal-coordinator/src/ln-modal-coordinator.js +345 -0
  94. package/js/ln-nav/README.md +46 -3
  95. package/js/ln-nav/ln-nav.js +1 -1
  96. package/js/ln-nav/src/ln-nav.js +92 -127
  97. package/js/ln-number/README.md +28 -1
  98. package/js/ln-number/ln-number-dev.scss +13 -0
  99. package/js/ln-number/ln-number.js +1 -1
  100. package/js/ln-number/src/ln-number.js +443 -350
  101. package/js/ln-options/README.md +66 -0
  102. package/js/ln-options/ln-options.js +1 -0
  103. package/js/ln-options/src/ln-options.js +74 -0
  104. package/js/ln-popover/README.md +40 -5
  105. package/js/ln-popover/ln-popover.js +1 -1
  106. package/js/ln-popover/src/ln-popover.js +38 -11
  107. package/js/ln-progress/README.md +413 -442
  108. package/js/ln-progress/ln-progress.js +1 -1
  109. package/js/ln-progress/src/ln-progress.js +98 -150
  110. package/js/ln-router/README.md +432 -0
  111. package/js/ln-router/ln-router.js +1 -0
  112. package/js/ln-router/src/ln-router.js +539 -0
  113. package/js/ln-search/README.md +158 -83
  114. package/js/ln-search/ln-search-dev.scss +8 -0
  115. package/js/ln-search/ln-search.js +1 -1
  116. package/js/ln-search/src/ln-search.js +12 -9
  117. package/js/ln-slug/README.md +110 -0
  118. package/js/ln-slug/ln-slug.js +1 -0
  119. package/js/ln-slug/src/ln-slug.js +74 -0
  120. package/js/ln-sort/README.md +170 -0
  121. package/js/ln-sort/ln-sort-dev.scss +8 -0
  122. package/js/ln-sort/ln-sort.js +1 -0
  123. package/js/ln-sort/src/ln-sort.js +178 -0
  124. package/js/ln-sortable/README.md +133 -95
  125. package/js/ln-sortable/ln-sortable.js +1 -1
  126. package/js/ln-stat/README.md +55 -0
  127. package/js/ln-stat/ln-stat.js +1 -0
  128. package/js/ln-stat/src/ln-stat.js +55 -0
  129. package/js/ln-table/README.md +285 -101
  130. package/js/ln-table/ln-table-dev.scss +17 -0
  131. package/js/ln-table/ln-table.js +1 -1
  132. package/js/ln-table/ln-table.scss +1 -1
  133. package/js/ln-table/src/ln-table.js +1493 -473
  134. package/js/ln-table-coordinator/README.md +73 -0
  135. package/js/ln-table-coordinator/ln-table-coordinator.js +1 -0
  136. package/js/ln-table-coordinator/src/ln-table-coordinator.js +160 -0
  137. package/js/ln-tabs/README.md +221 -137
  138. package/js/ln-tabs/ln-tabs-dev.scss +18 -0
  139. package/js/ln-tabs/ln-tabs.js +1 -1
  140. package/js/ln-tabs/src/ln-tabs.js +41 -24
  141. package/js/ln-time/README.md +14 -0
  142. package/js/ln-time/ln-time.js +1 -1
  143. package/js/ln-time/src/ln-time.js +223 -192
  144. package/js/ln-toast/README.md +178 -122
  145. package/js/ln-toast/ln-toast.js +1 -15
  146. package/js/ln-toast/src/ln-toast.js +232 -210
  147. package/js/ln-toast/template.html +16 -12
  148. package/js/ln-toggle/README.md +61 -2
  149. package/js/ln-toggle/ln-toggle-dev.scss +13 -0
  150. package/js/ln-toggle/ln-toggle.js +1 -1
  151. package/js/ln-toggle/src/ln-toggle.js +56 -43
  152. package/js/ln-tooltip/README.md +95 -58
  153. package/js/ln-tooltip/ln-tooltip-dev.scss +9 -0
  154. package/js/ln-tooltip/ln-tooltip.js +1 -1
  155. package/js/ln-tooltip/src/ln-tooltip.js +45 -6
  156. package/js/ln-translations/README.md +118 -96
  157. package/js/ln-translations/ln-translations.js +1 -1
  158. package/js/ln-translations/src/ln-translations.js +10 -5
  159. package/js/ln-upload/README.md +85 -10
  160. package/js/ln-upload/ln-upload.js +1 -1
  161. package/js/ln-upload/src/ln-upload.js +26 -10
  162. package/js/ln-validate/README.md +72 -0
  163. package/js/ln-validate/ln-validate-dev.scss +15 -0
  164. package/js/ln-validate/ln-validate.js +1 -1
  165. package/js/ln-validate/src/ln-validate.js +64 -0
  166. package/package.json +61 -55
  167. package/scss/base/_global.scss +2 -2
  168. package/scss/base/_typography.scss +1 -2
  169. package/scss/components/_date.scss +1 -0
  170. package/scss/components/_dropdown.scss +0 -5
  171. package/scss/components/_editor.scss +5 -0
  172. package/scss/components/_filter.scss +26 -0
  173. package/scss/components/_form.scss +7 -0
  174. package/scss/components/_ln-table.scss +14 -5
  175. package/scss/components/_sort.scss +10 -0
  176. package/scss/components/_table.scss +68 -1
  177. package/scss/components/_toast.scss +68 -41
  178. package/scss/components/_toggle.scss +16 -0
  179. package/scss/config/_density.scss +205 -117
  180. package/scss/config/_icons.scss +10 -9
  181. package/scss/config/_tokens.scss +69 -47
  182. package/scss/config/mixins/_accordion.scss +2 -7
  183. package/scss/config/mixins/_alert.scss +4 -4
  184. package/scss/config/mixins/_breadcrumbs.scss +2 -2
  185. package/scss/config/mixins/_btn.scss +1 -1
  186. package/scss/config/mixins/_card.scss +89 -14
  187. package/scss/config/mixins/_collapsible.scss +3 -0
  188. package/scss/config/mixins/_colors.scss +1 -1
  189. package/scss/config/mixins/_diagnostics.scss +48 -0
  190. package/scss/config/mixins/_display.scss +1 -0
  191. package/scss/config/mixins/_dropdown.scss +3 -5
  192. package/scss/config/mixins/_editor.scss +124 -0
  193. package/scss/config/mixins/_empty-state.scss +7 -0
  194. package/scss/config/mixins/_filter.scss +47 -0
  195. package/scss/config/mixins/_footer.scss +1 -2
  196. package/scss/config/mixins/_form.scss +207 -21
  197. package/scss/config/mixins/_index.scss +4 -1
  198. package/scss/config/mixins/_ln-table.scss +51 -93
  199. package/scss/config/mixins/_modal.scss +149 -66
  200. package/scss/config/mixins/_nav.scss +3 -4
  201. package/scss/config/mixins/_popover.scss +39 -0
  202. package/scss/config/mixins/_sidebar.scss +1 -1
  203. package/scss/config/mixins/_sort.scss +42 -0
  204. package/scss/config/mixins/_table.scss +232 -38
  205. package/scss/config/mixins/_toast.scss +179 -152
  206. package/scss/config/mixins/_tooltip.scss +17 -7
  207. package/scss/config/mixins/_typography.scss +4 -2
  208. package/scss/ln-ashlar-dev.scss +39 -0
  209. package/scss/ln-ashlar.scss +8 -2
  210. package/js/ln-data-table/README.md +0 -110
  211. package/js/ln-data-table/ln-data-table.js +0 -1
  212. package/js/ln-data-table/ln-data-table.scss +0 -10
  213. package/js/ln-data-table/src/ln-data-table.js +0 -1103
  214. package/js/ln-icons/README.md +0 -88
  215. package/js/ln-icons/ln-icons.js +0 -1
  216. package/js/ln-table/ln-table-sort.js +0 -1
  217. package/js/ln-table/src/ln-table-sort.js +0 -168
  218. package/scss/components/_data-table.scss +0 -83
  219. package/scss/config/mixins/_data-table.scss +0 -346
@@ -1 +1 @@
1
- (function(){"use strict";function R(s,n,u){s.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:u||{}}))}function D(s,n){if(!s||!n)return s;const u=document.createTreeWalker(s,NodeFilter.SHOW_TEXT);for(;u.nextNode();){const c=u.currentNode;c.textContent.indexOf("{{")!==-1&&(c.textContent=c.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(m,h){return n[h]!==void 0?n[h]:""}))}return s}function B(s,n){if(!document.body){document.addEventListener("DOMContentLoaded",function(){B(s,n)}),console.warn("["+n+'] Script loaded before <body> — add "defer" to your <script> tag');return}s()}function S(s,n,u,c){if(s.nodeType!==1)return;const h=n.indexOf("[")!==-1||n.indexOf(".")!==-1||n.indexOf("#")!==-1?n:"["+n+"]",T=Array.from(s.querySelectorAll(h));s.matches&&s.matches(h)&&T.push(s);for(const y of T)y[u]||(y[u]=new c(y))}function F(s,n,u,c,m={}){const h=m.extraAttributes||[],T=m.onAttributeChange||null,y=m.onInit||null;function A(b){const _=b||document.body;S(_,s,n,u),y&&y(_)}return B(function(){const b=new MutationObserver(function(I){for(let w=0;w<I.length;w++){const f=I[w];if(f.type==="childList"){for(let t=0;t<f.addedNodes.length;t++){const e=f.addedNodes[t];e.nodeType===1&&(S(e,s,n,u),y&&y(e))}for(let t=0;t<f.removedNodes.length;t++){const e=f.removedNodes[t];if(e.nodeType===1){const r=s.indexOf("[")!==-1||s.indexOf(".")!==-1||s.indexOf("#")!==-1?s:"["+s+"]",o=Array.from(e.querySelectorAll(r));e.matches&&e.matches(r)&&o.push(e);for(let l=0;l<o.length;l++){const d=o[l];if(!document.contains(d)){const a=d[n];a&&typeof a.destroy=="function"&&a.destroy()}}}}}else f.type==="attributes"&&(T&&f.target[n]?T(f.target,f.attributeName):(S(f.target,s,n,u),y&&y(f.target)))}});let _=[];if(s.indexOf("[")!==-1){const I=/\[([\w-]+)/g;let w;for(;(w=I.exec(s))!==null;)_.push(w[1])}else _.push(s);b.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:_.concat(h)})},c),window[n]=A,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){A(document.body)}):A(document.body),A}const L={};function K(s,n){L[s]=n}function j(s){return L[s]||{ingress:n=>n,egress:n=>n}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=K,window.lnCore.getDataMapper=j);function H(s,n){let u=!1;return function(){u||(u=!0,queueMicrotask(function(){u=!1,s(),n&&n()}))}}const W="ln:";function J(){return location.pathname.replace(/\/+$/,"").toLowerCase()||"/"}function q(s,n){const u=n.getAttribute("data-ln-persist"),c=u!==null&&u!==""?u:n.id;return c?W+s+":"+J()+":"+c:(console.warn('[ln-persist] Element requires id or data-ln-persist="key"',n),null)}function U(s,n){const u=q(s,n);if(!u)return null;try{const c=localStorage.getItem(u);return c!==null?JSON.parse(c):null}catch{return null}}function N(s,n,u){const c=q(s,n);if(c)try{localStorage.setItem(c,JSON.stringify(u))}catch{}}(function(){const s="data-ln-filter",n="lnFilter",u="data-ln-filter-initialized",c="data-ln-filter-key",m="data-ln-filter-value",h="data-ln-filter-hide",T="data-ln-filter-reset",y="data-ln-filter-col",A=new WeakMap;if(window[n]!==void 0)return;function b(t){return t.hasAttribute(T)||t.getAttribute(m)===""}function _(t){let e=null;const i=[];for(let r=0;r<t.inputs.length;r++){const o=t.inputs[r];if(o.checked&&!b(o)){e===null&&(e=o.getAttribute(c));const l=o.getAttribute(m);l&&i.push(l)}}return{key:e,values:i}}function I(t,e){if(t.length!==e.length)return!0;for(let i=0;i<t.length;i++)if(t[i]!==e[i])return!0;return!1}function w(t){const e=t.dom,i=t.colIndex,r=e.querySelector("template");if(!r||i===null)return;const o=document.getElementById(t.targetId);if(!o)return;const l=o.tagName==="TABLE"?o:o.querySelector("table");if(!l||o.hasAttribute("data-ln-table"))return;const d={},a=[],x=l.tBodies;for(let g=0;g<x.length;g++){const p=x[g].rows;for(let v=0;v<p.length;v++){const O=p[v].cells[i],E=O?O.textContent.trim():"";E&&!d[E]&&(d[E]=!0,a.push(E))}}a.sort(function(g,p){return g.localeCompare(p)});const k=e.querySelector("["+c+"]"),C=k?k.getAttribute(c):e.getAttribute("data-ln-filter-key")||"col"+i;for(let g=0;g<a.length;g++){const p=r.content.cloneNode(!0),v=p.querySelector("input");v&&(v.setAttribute(c,C),v.setAttribute(m,a[g]),D(p,{text:a[g]}),e.appendChild(p))}}function f(t){if(t.hasAttribute(u))return this;this.dom=t,this.targetId=t.getAttribute(s);const e=t.getAttribute(y);this.colIndex=e!==null?parseInt(e,10):null,w(this),this.inputs=Array.from(t.querySelectorAll("["+c+"]")),this._filterKey=this.inputs.length>0?this.inputs[0].getAttribute(c):null,this._lastSnapshot=null;const i=this,r=H(function(){i._render()},function(){i._afterRender()});this._queueRender=r,this._attachHandlers();let o=!1;if(t.hasAttribute("data-ln-persist")){const l=U("filter",t);if(l&&l.key&&Array.isArray(l.values)&&l.values.length>0){for(let d=0;d<this.inputs.length;d++){const a=this.inputs[d];b(a)?a.checked=!1:a.getAttribute(c)===l.key&&l.values.indexOf(a.getAttribute(m))!==-1?a.checked=!0:a.checked=!1}r(),o=!0}}if(!o){for(let l=0;l<this.inputs.length;l++)if(this.inputs[l].checked&&!b(this.inputs[l])){r();break}}return t.setAttribute(u,""),this}f.prototype._attachHandlers=function(){const t=this;this.inputs.forEach(function(e){e[n+"Bound"]||(e[n+"Bound"]=!0,e._lnFilterChange=function(){if(b(e)){for(let i=0;i<t.inputs.length;i++)b(t.inputs[i])||(t.inputs[i].checked=!1);e.checked=!0,t._queueRender();return}if(e.checked)for(let i=0;i<t.inputs.length;i++)b(t.inputs[i])&&(t.inputs[i].checked=!1);else{let i=!1;for(let r=0;r<t.inputs.length;r++)if(!b(t.inputs[r])&&t.inputs[r].checked){i=!0;break}if(!i)for(let r=0;r<t.inputs.length;r++)b(t.inputs[r])&&(t.inputs[r].checked=!0)}t._queueRender()},e.addEventListener("change",e._lnFilterChange))})},f.prototype._render=function(){const t=this,e=_(this),i=e.key===null||e.values.length===0,r=[];for(let o=0;o<e.values.length;o++)r.push(e.values[o].toLowerCase());if(t.colIndex!==null)t._filterTableRows(e);else{const o=document.getElementById(t.targetId);if(!o)return;const l=o.children;for(let d=0;d<l.length;d++){const a=l[d];if(i){a.removeAttribute(h);continue}const x=a.getAttribute("data-"+e.key);a.removeAttribute(h),x!==null&&r.indexOf(x.toLowerCase())===-1&&a.setAttribute(h,"true")}}},f.prototype._afterRender=function(){const t=_(this),e=this._lastSnapshot;if(!e||e.key!==t.key||I(e.values,t.values)){this._dispatchOnBoth("ln-filter:changed",{key:t.key,values:t.values.slice()});const r=e&&e.values.length>0,o=t.values.length===0;r&&o&&this._dispatchOnBoth("ln-filter:reset",{}),this._lastSnapshot={key:t.key,values:t.values.slice()}}this.dom.hasAttribute("data-ln-persist")&&(t.key&&t.values.length>0?N("filter",this.dom,{key:t.key,values:t.values.slice()}):N("filter",this.dom,null))},f.prototype._dispatchOnBoth=function(t,e){R(this.dom,t,e);const i=document.getElementById(this.targetId);i&&i!==this.dom&&R(i,t,e)},f.prototype._filterTableRows=function(t){const e=document.getElementById(this.targetId);if(!e)return;const i=e.tagName==="TABLE"?e:e.querySelector("table");if(!i||e.hasAttribute("data-ln-table"))return;const r=t.key||this._filterKey,o=t.values;A.has(i)||A.set(i,{});const l=A.get(i);if(r&&o.length>0){const k=[];for(let C=0;C<o.length;C++)k.push(o[C].toLowerCase());l[r]={col:this.colIndex,values:k}}else r&&delete l[r];const d=Object.keys(l),a=d.length>0,x=i.tBodies;for(let k=0;k<x.length;k++){const C=x[k].rows;for(let g=0;g<C.length;g++){const p=C[g];if(!a){p.removeAttribute(h);continue}let v=!0;for(let O=0;O<d.length;O++){const E=l[d[O]],M=p.cells[E.col],V=M?M.textContent.trim().toLowerCase():"";if(E.values.indexOf(V)===-1){v=!1;break}}v?p.removeAttribute(h):p.setAttribute(h,"true")}}},f.prototype.destroy=function(){if(this.dom[n]){if(this.colIndex!==null){const t=document.getElementById(this.targetId);if(t){const e=t.tagName==="TABLE"?t:t.querySelector("table");if(e&&A.has(e)){const i=A.get(e),r=this._filterKey;r&&i[r]&&delete i[r],Object.keys(i).length===0&&A.delete(e)}}}this.inputs.forEach(function(t){t._lnFilterChange&&(t.removeEventListener("change",t._lnFilterChange),delete t._lnFilterChange),delete t[n+"Bound"]}),this.dom.removeAttribute(u),delete this.dom[n]}},F(s,n,f,"ln-filter")})()})();
1
+ (function(){"use strict";if(typeof window<"u"){const t=console.warn;console.warn=function(...n){typeof n[0]=="string"&&(n[0].startsWith("[ln-")||n[0].startsWith("[lnCore"))&&!(document.documentElement.hasAttribute("data-ln-debug")||document.body&&document.body.hasAttribute("data-ln-debug"))||t.apply(console,n)}}const I={};function J(t,n){I[t]||(I[t]=document.querySelector('[data-ln-template="'+t+'"]'));const l=I[t];return l?l.content.cloneNode(!0):(console.warn("["+(n||"ln-core")+'] Template "'+t+'" not found'),null)}function B(t,n,l){t.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:l||{}}))}function F(t,n){if(!t||!n)return t;const l=t.querySelectorAll("[data-ln-field]");for(let u=0;u<l.length;u++){const c=l[u],s=c.getAttribute("data-ln-field");n[s]!=null&&(c.textContent=n[s])}const f=t.querySelectorAll("[data-ln-attr]");for(let u=0;u<f.length;u++){const c=f[u],s=c.getAttribute("data-ln-attr").split(",");for(let d=0;d<s.length;d++){const m=s[d].trim().split(":");if(m.length!==2)continue;const w=m[0].trim(),y=m[1].trim();n[y]!=null&&c.setAttribute(w,n[y])}}const p=t.querySelectorAll("[data-ln-show]");for(let u=0;u<p.length;u++){const c=p[u],s=c.getAttribute("data-ln-show");s in n&&c.classList.toggle("hidden",!n[s])}const g=t.querySelectorAll("[data-ln-class]");for(let u=0;u<g.length;u++){const c=g[u],s=c.getAttribute("data-ln-class").split(",");for(let d=0;d<s.length;d++){const m=s[d].trim().split(":");if(m.length!==2)continue;const w=m[0].trim(),y=m[1].trim();y in n&&c.classList.toggle(w,!!n[y])}}return t}function P(t,n){t.matches&&t.matches("[data-ln-form], [data-ln-fillable]")&&t.dispatchEvent(new CustomEvent("ln-fill",{detail:n??null,bubbles:!0}));const l=t.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let f=0;f<l.length;f++)l[f].dispatchEvent(new CustomEvent("ln-fill",{detail:n??null,bubbles:!0}));return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(t){if(!(!t.target.matches||!t.target.matches("[data-ln-fillable]")))if(t.detail)F(t.target,t.detail);else{const n=t.target.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++)n[l].textContent=""}})));function O(t,n){if(!t||!n)return t;const l=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(;l.nextNode();){const g=l.currentNode;g.textContent.indexOf("{{")!==-1&&(g.textContent=g.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(u,c){return n[c]!==void 0?n[c]:""}))}const f=function(g,u){return n[u]!==void 0?n[u]:""},p=Array.from(t.querySelectorAll("*"));t.nodeType===1&&p.push(t);for(let g=0;g<p.length;g++){const u=p[g],c=u.attributes;for(let s=0;s<c.length;s++){const d=c[s];d.value.indexOf("{{")!==-1&&u.setAttribute(d.name,d.value.replace(/\{\{\s*(\w+)\s*\}\}/g,f))}}return t}function V(t,n,l,f,p,g){const u={};for(let s=0;s<t.children.length;s++){const d=t.children[s],m=d.getAttribute("data-ln-key");m&&(u[m]=d)}const c=document.createDocumentFragment();for(let s=0;s<n.length;s++){const d=n[s],m=String(f(d));let w=u[m];if(w)p(w,d,s);else{const y=J(l,g);if(!y||(O(y,d),w=y.firstElementChild,!w))continue;w.setAttribute("data-ln-key",m),p(w,d,s)}c.appendChild(w)}t.textContent="",t.appendChild(c)}function D(t,n){if(!document.body){document.addEventListener("DOMContentLoaded",function(){D(t,n)}),console.warn("["+n+'] Script loaded before <body> — add "defer" to your <script> tag');return}t()}function q(t,n,l,f){if(t.nodeType!==1)return;const g=n.indexOf("[")!==-1||n.indexOf(".")!==-1||n.indexOf("#")!==-1?n:"["+n+"]",u=Array.from(t.querySelectorAll(g));t.matches&&t.matches(g)&&u.push(t);for(const c of u)c[l]||(c[l]=new f(c))}function X(t,n,l,f,p={}){const g=p.extraAttributes||[],u=p.onAttributeChange||null,c=p.onInit||null;function s(d){const m=d||document.body;q(m,t,n,l),c&&c(m)}return D(function(){const d=new MutationObserver(function(w){for(let y=0;y<w.length;y++){const e=w[y];if(e.type==="childList"){for(let i=0;i<e.addedNodes.length;i++){const r=e.addedNodes[i];r.nodeType===1&&(q(r,t,n,l),c&&c(r))}for(let i=0;i<e.removedNodes.length;i++){const r=e.removedNodes[i];if(r.nodeType===1){const a=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",h=Array.from(r.querySelectorAll(a));r.matches&&r.matches(a)&&h.push(r);for(let A=0;A<h.length;A++){const b=h[A];if(!document.contains(b)){const v=b[n];v&&typeof v.destroy=="function"&&v.destroy()}}}}}else e.type==="attributes"&&(u&&e.target[n]?u(e.target,e.attributeName):(q(e.target,t,n,l),c&&c(e.target)))}});let m=[];if(t.indexOf("[")!==-1){const w=/\[([\w-]+)/g;let y;for(;(y=w.exec(t))!==null;)m.push(y[1])}else m.push(t);d.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:m.concat(g)})},f),window[n]=s,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){s(document.body)}):s(document.body),s}const K={};function Y(t,n){K[t]=n}function $(t){return K[t]||{ingress:n=>n,egress:n=>n}}const N={};function M(t,n){if(!t||typeof n!="object")return;const l=t.toLowerCase().split("-")[0];N[l]=n}function z(t){if(!t)return null;const n=t.toLowerCase().split("-")[0];return N[n]||null}M("mk",{monthsLong:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],monthsShort:["јан","фев","мар","апр","мај","јун","јул","авг","септ","окт","ноем","дек"],daysLong:["недела","понеделник","вторник","среда","четврток","петок","сабота"],daysShort:["нед","пон","вт","ср","чет","пет","саб"]}),typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=Y,window.lnCore.getDataMapper=$,window.lnCore.registerLocaleFallback=M,window.lnCore.getLocaleFallback=z,window.lnCore.fillTemplate=O,window.lnCore.fill=F,window.lnCore.lnFill=P,window.lnCore.renderList=V);function Q(t,n){let l=!1;return function(){l||(l=!0,queueMicrotask(function(){l=!1,t(),n&&n()}))}}const Z="ln:";let E=null;function j(){if(E!==null)return E;try{if(typeof localStorage>"u")return E=!1,!1;const t="__ln_test__";localStorage.setItem(t,t),localStorage.removeItem(t),E=!0}catch{E=!1}return E}function tt(){return location.pathname.replace(/\/+$/,"").toLowerCase()||"/"}function W(t,n){const l=n.getAttribute("data-ln-persist"),f=l!==null&&l!==""?l:n.id;return f?Z+t+":"+tt()+":"+f:(console.warn('[ln-persist] Element requires id or data-ln-persist="key"',n),null)}function et(t,n){if(!j())return null;const l=W(t,n);if(!l)return null;try{const f=localStorage.getItem(l);return f!==null?JSON.parse(f):null}catch{return null}}function H(t,n,l){if(!j())return;const f=W(t,n);if(f)try{l==null?localStorage.removeItem(f):localStorage.setItem(f,JSON.stringify(l))}catch{}}function U(t){return(t||"").replace(/^#/,"")}function R(t){const n=t===void 0?location.hash:t,l={},f=U(n);if(!f)return l;const p=f.split("&");for(let g=0;g<p.length;g++){const u=p[g];if(!u)continue;const c=u.indexOf(":"),s=c>-1?u.slice(0,c):u,d=c>-1?u.slice(c+1):"";if(s)try{l[s]=decodeURIComponent(d)}catch{l[s]=d}}return l}function nt(t){if(!t)return null;const n=R();return t in n?n[t]:null}function lt(t,n){if(!t)return;const l=R();n==null?delete l[t]:l[t]=String(n);const p=Object.keys(l).map(function(g){const u=l[g];return u===""?g:g+":"+encodeURIComponent(u)}).join("&");U(location.hash)!==p&&(location.hash=p)}function it(t){return t.button===1||t.ctrlKey||t.metaKey||t.shiftKey?!1:(t.preventDefault(),!0)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=R,window.lnCore.hashGet=nt,window.lnCore.hashSet=lt,window.lnCore.hashLinkClick=it),(function(){const t="data-ln-filter",n="lnFilter",l="data-ln-filter-key",f="data-ln-filter-value",p="data-ln-filter-hide",g="data-ln-filter-reset",u="data-ln-filter-col",c=new WeakMap;if(window[n]!==void 0)return;function s(e){return e.hasAttribute(g)||e.getAttribute(f)===""}function d(e){let i=e._filterKey;const r=[];for(let o=0;o<e.inputs.length;o++){const a=e.inputs[o];if(a.checked&&!s(a)){const h=a.getAttribute(f);h&&r.push(h)}}return{key:i,values:r}}function m(e,i){if(e.length!==i.length)return!0;for(let r=0;r<e.length;r++)if(e[r]!==i[r])return!0;return!1}function w(e){const i=e.dom,r=e.colIndex,o=i.querySelector("template");if(!o||r===null)return;const a=document.getElementById(e.targetId);if(!a)return;const h=a.tagName==="TABLE"?a:a.querySelector("table");if(!h||a.hasAttribute("data-ln-table"))return;const A={},b=[],v=h.tBodies;for(let k=0;k<v.length;k++){const C=v[k].rows;for(let _=0;_<C.length;_++){const T=C[_].cells[r],L=T?T.textContent.trim():"";L&&!A[L]&&(A[L]=!0,b.push(L))}}b.sort(function(k,C){return k.localeCompare(C)});const x=i.querySelector("["+l+"]"),S=x?x.getAttribute(l):i.getAttribute("data-ln-filter-key")||"col"+r;for(let k=0;k<b.length;k++){const C=o.content.cloneNode(!0),_=C.querySelector("input");_&&(_.setAttribute(l,S),_.setAttribute(f,b[k]),O(C,{text:b[k]}),i.appendChild(C))}}function y(e){this.dom=e,this.targetId=e.getAttribute(t);const i=e.getAttribute(u);this.colIndex=i!==null?parseInt(i,10):null,w(this),this.inputs=Array.from(e.querySelectorAll("["+l+"]")),this._filterKey=this.inputs.length>0?this.inputs[0].getAttribute(l):null,this._lastSnapshot=null;const r=this,o=Q(function(){r._render()},function(){r._afterRender()});this._queueRender=o,this._attachHandlers();let a=!1;if(e.hasAttribute("data-ln-persist")){const h=et("filter",e);if(h&&h.key&&Array.isArray(h.values)&&h.values.length>0){for(let A=0;A<this.inputs.length;A++){const b=this.inputs[A];s(b)?b.checked=!1:b.getAttribute(l)===h.key&&h.values.indexOf(b.getAttribute(f))!==-1?b.checked=!0:b.checked=!1}o(),a=!0}}if(!a){for(let h=0;h<this.inputs.length;h++)if(this.inputs[h].checked&&!s(this.inputs[h])){o();break}}return this}y.prototype._attachHandlers=function(){const e=this;this.inputs.forEach(function(i){i[n+"Bound"]||(i[n+"Bound"]=!0,i._lnFilterChange=function(){if(s(i)){for(let r=0;r<e.inputs.length;r++)s(e.inputs[r])||(e.inputs[r].checked=!1);i.checked=!0,e._queueRender();return}if(i.checked){for(let o=0;o<e.inputs.length;o++)s(e.inputs[o])&&(e.inputs[o].checked=!1);let r=!1;for(let o=0;o<e.inputs.length;o++)if(s(e.inputs[o])){r=!0;break}if(r){let o=!0;for(let a=0;a<e.inputs.length;a++)if(!s(e.inputs[a])&&!e.inputs[a].checked){o=!1;break}if(o)for(let a=0;a<e.inputs.length;a++)s(e.inputs[a])?e.inputs[a].checked=!0:e.inputs[a].checked=!1}}else{let r=!1;for(let o=0;o<e.inputs.length;o++)if(!s(e.inputs[o])&&e.inputs[o].checked){r=!0;break}if(!r)for(let o=0;o<e.inputs.length;o++)s(e.inputs[o])&&(e.inputs[o].checked=!0)}e._queueRender()},i.addEventListener("change",i._lnFilterChange))})},y.prototype._render=function(){const e=this,i=d(this),r=i.key===null||i.values.length===0,o=[];for(let a=0;a<i.values.length;a++)o.push(i.values[a].toLowerCase());if(e.colIndex!==null)e._filterTableRows(i);else{const a=document.getElementById(e.targetId);if(!a)return;const h=a.children;for(let A=0;A<h.length;A++){const b=h[A];if(r){b.removeAttribute(p);continue}const v=b.getAttribute("data-"+i.key);b.removeAttribute(p),v!==null&&o.indexOf(v.toLowerCase())===-1&&b.setAttribute(p,"true")}}},y.prototype._afterRender=function(){const e=d(this),i=this._lastSnapshot;if(!i||i.key!==e.key||m(i.values,e.values)){this._dispatchOnBoth("ln-filter:changed",{key:e.key,values:e.values.slice()});const o=i&&i.values.length>0,a=e.values.length===0;o&&a&&this._dispatchOnBoth("ln-filter:reset",{}),this._lastSnapshot={key:e.key,values:e.values.slice()}}this.dom.hasAttribute("data-ln-persist")&&(e.key&&e.values.length>0?H("filter",this.dom,{key:e.key,values:e.values.slice()}):H("filter",this.dom,null))},y.prototype._dispatchOnBoth=function(e,i){B(this.dom,e,i);const r=document.getElementById(this.targetId);r&&r!==this.dom&&B(r,e,i)},y.prototype._filterTableRows=function(e){const i=document.getElementById(this.targetId);if(!i)return;const r=i.tagName==="TABLE"?i:i.querySelector("table");if(!r||i.hasAttribute("data-ln-table"))return;const o=e.key||this._filterKey,a=e.values;c.has(r)||c.set(r,{});const h=c.get(r);if(o&&a.length>0){const x=[];for(let S=0;S<a.length;S++)x.push(a[S].toLowerCase());h[o]={col:this.colIndex,values:x}}else o&&delete h[o];const A=Object.keys(h),b=A.length>0,v=r.tBodies;for(let x=0;x<v.length;x++){const S=v[x].rows;for(let k=0;k<S.length;k++){const C=S[k];if(!b){C.removeAttribute(p);continue}let _=!0;for(let T=0;T<A.length;T++){const L=h[A[T]],G=C.cells[L.col],rt=G?G.textContent.trim().toLowerCase():"";if(L.values.indexOf(rt)===-1){_=!1;break}}_?C.removeAttribute(p):C.setAttribute(p,"true")}}},y.prototype.destroy=function(){if(this.dom[n]){if(this.colIndex!==null){const e=document.getElementById(this.targetId);if(e){const i=e.tagName==="TABLE"?e:e.querySelector("table");if(i&&c.has(i)){const r=c.get(i),o=this._filterKey;o&&r[o]&&delete r[o],Object.keys(r).length===0&&c.delete(i)}}}this.inputs.forEach(function(e){e._lnFilterChange&&(e.removeEventListener("change",e._lnFilterChange),delete e._lnFilterChange),delete e[n+"Bound"]}),delete this.dom[n]}},X(t,n,y,"ln-filter")})()})();
@@ -5,7 +5,6 @@ import { persistGet, persistSet } from '../../ln-core';
5
5
  (function () {
6
6
  const DOM_SELECTOR = 'data-ln-filter';
7
7
  const DOM_ATTRIBUTE = 'lnFilter';
8
- const INIT_ATTR = 'data-ln-filter-initialized';
9
8
  const KEY_ATTR = 'data-ln-filter-key';
10
9
  const VALUE_ATTR = 'data-ln-filter-value';
11
10
  const HIDE_ATTR = 'data-ln-filter-hide';
@@ -22,12 +21,11 @@ import { persistGet, persistSet } from '../../ln-core';
22
21
  }
23
22
 
24
23
  function _deriveActive(self) {
25
- let key = null;
24
+ let key = self._filterKey;
26
25
  const values = [];
27
26
  for (let i = 0; i < self.inputs.length; i++) {
28
27
  const input = self.inputs[i];
29
28
  if (input.checked && !_isReset(input)) {
30
- if (key === null) key = input.getAttribute(KEY_ATTR);
31
29
  const v = input.getAttribute(VALUE_ATTR);
32
30
  if (v) values.push(v);
33
31
  }
@@ -95,8 +93,6 @@ import { persistGet, persistSet } from '../../ln-core';
95
93
  // ─── Component ─────────────────────────────────────────────
96
94
 
97
95
  function _component(dom) {
98
- if (dom.hasAttribute(INIT_ATTR)) return this;
99
-
100
96
  this.dom = dom;
101
97
  this.targetId = dom.getAttribute(DOM_SELECTOR);
102
98
 
@@ -160,7 +156,6 @@ import { persistGet, persistSet } from '../../ln-core';
160
156
  }
161
157
  }
162
158
 
163
- dom.setAttribute(INIT_ATTR, '');
164
159
  return this;
165
160
  }
166
161
 
@@ -191,6 +186,27 @@ import { persistGet, persistSet } from '../../ln-core';
191
186
  for (let i = 0; i < self.inputs.length; i++) {
192
187
  if (_isReset(self.inputs[i])) self.inputs[i].checked = false;
193
188
  }
189
+ // If all non-reset inputs are now checked → collapse to sentinel
190
+ // (only when a reset sentinel exists; lists without one skip this)
191
+ let hasReset = false;
192
+ for (let ri = 0; ri < self.inputs.length; ri++) {
193
+ if (_isReset(self.inputs[ri])) { hasReset = true; break; }
194
+ }
195
+ if (hasReset) {
196
+ let allChecked = true;
197
+ for (let ci = 0; ci < self.inputs.length; ci++) {
198
+ if (!_isReset(self.inputs[ci]) && !self.inputs[ci].checked) {
199
+ allChecked = false;
200
+ break;
201
+ }
202
+ }
203
+ if (allChecked) {
204
+ for (let mi = 0; mi < self.inputs.length; mi++) {
205
+ if (_isReset(self.inputs[mi])) self.inputs[mi].checked = true;
206
+ else self.inputs[mi].checked = false;
207
+ }
208
+ }
209
+ }
194
210
  } else {
195
211
  // If no non-reset values remain checked, fall back to reset
196
212
  let anyChecked = false;
@@ -394,7 +410,6 @@ import { persistGet, persistSet } from '../../ln-core';
394
410
  }
395
411
  delete input[DOM_ATTRIBUTE + 'Bound'];
396
412
  });
397
- this.dom.removeAttribute(INIT_ATTR);
398
413
  delete this.dom[DOM_ATTRIBUTE];
399
414
  };
400
415
 
@@ -1,101 +1,264 @@
1
1
  # ln-form
2
2
 
3
- A high-performance **Form Coordinator** that upgrades native HTML forms. It acts as the orchestration layer: coordinating bulk population (`fill`), native reset procedures, reactive validation state gating, and debounced auto-submission.
4
-
5
- It delegates per-field validation rules to the `ln-validate` primitive and visual formatting to SCSS layout mixins, focusing purely on gating the submission flow and serializing form data into clean JSON.
3
+ A minimal **form manipulation** primitive. `ln-form` does exactly two
4
+ things to a native `<form>`: populate it when an `ln-fill` event delivers
5
+ a record, and rewrite `action` / `_method` for RESTful edit routing.
6
+ Submit is entirely native HTML — `ln-form` does not listen for `submit`
7
+ at all. Validation display and the submit gate are owned entirely by
8
+ [`ln-validate`](../ln-validate/README.md).
6
9
 
7
10
  ---
8
11
 
9
- ## 🧭 Philosophy & Architecture
12
+ ## 1. Philosophy
10
13
 
11
- 1. **The Form as Coordinator:** `ln-form` maintains no internal registry of validation rules or values. It listens to bubbled DOM events (`ln-validate:valid`, `ln-validate:invalid`) and enforces a single rule: *the form submit button is disabled until all marked fields are valid and at least one has been touched.*
12
- 2. **Zero Network Coupling:** The component does not make XHR or fetch requests. On successful submission, it serializes values and dispatches an uncancellable `ln-form:submit` CustomEvent carrying the payload. Network integration belongs entirely in a separate transport layer (`ln-http` or a custom controller).
13
- 3. **Reactive Integrity:** Data flows strictly through DOM events. Programmatic changes must trigger standard events (`input` / `change`) so that dependent primitives (`ln-validate`, `ln-autoresize`) can react in synchrony.
14
+ 1. **Populate, don't orchestrate.** `ln-form` writes values into the form
15
+ on `ln-fill` and dispatches synthetic `input`/`change` events so
16
+ reactive consumers (`ln-validate`, `ln-autoresize`) react in sync. It
17
+ keeps no validation state and no submit-button logic.
18
+ 2. **Native submit, always.** Forms MUST carry a real `action` and
19
+ `method` in HTML. Without JavaScript they do a normal native submit.
20
+ PUT/DELETE ride on POST via an auto-ensured hidden `_method` input
21
+ (Laravel method spoofing) — `ln-form` never serializes data, never
22
+ dispatches a submit event, and never listens for `submit` at all.
23
+ 3. **Transport is someone else's job.** Ajax interception (if wanted) is
24
+ a separate component's concern — it listens to the native `submit`
25
+ event itself. Validation is owned by the browser's constraint
26
+ validation plus `ln-validate` for field error display and the submit
27
+ gate — a form with at least one `data-ln-validate` field gets
28
+ `novalidate` injected automatically and the first such field attaches
29
+ the form's submit gate; a form with none keeps native validation as
30
+ the default.
14
31
 
15
32
  ---
16
33
 
17
- ## 📦 Minimal Blueprint
34
+ ## 2. Minimal Blueprint
18
35
 
19
36
  ```html
20
- <form id="user-form" data-ln-form>
21
- <!-- Sibling elements wrapped in a semantic form-element -->
22
- <div class="form-element">
23
- <label for="username">Username</label>
24
- <input id="username" name="username" required data-ln-validate>
25
- <ul data-ln-validate-errors>
26
- <li class="hidden" data-ln-validate-error="required">Username is required</li>
27
- </ul>
28
- </div>
29
-
30
- <!-- Form Actions Footer -->
31
- <ul class="form-actions">
32
- <li><button type="button" data-ln-modal-close>Cancel</button></li>
33
- <li><button type="submit">Save</button></li>
34
- </ul>
37
+ <form id="user-form" data-ln-form action="/users" method="post">
38
+ <div class="form-element">
39
+ <label for="username">Username</label>
40
+ <input id="username" name="username" required data-ln-validate>
41
+ <ul data-ln-validate-errors>
42
+ <li hidden data-ln-validate-error="required">Username is required</li>
43
+ </ul>
44
+ </div>
45
+
46
+ <ul class="form-actions">
47
+ <li><button type="button" data-ln-modal-close>Cancel</button></li>
48
+ <li><button type="submit">Save</button></li>
49
+ </ul>
35
50
  </form>
36
51
  ```
37
52
 
38
53
  > [!WARNING]
39
- > Always set `type="button"` on Cancel buttons. Otherwise, the browser defaults to `type="submit"` and triggers validation/submission.
54
+ > Always set `type="button"` on Cancel buttons. Otherwise the browser
55
+ > defaults to `type="submit"` and triggers a real submit.
40
56
 
41
57
  ---
42
58
 
43
- ## 🛠️ Declarative API Contract
59
+ ## 3. Declarative API Contract
44
60
 
45
61
  ### HTML Attributes
46
62
 
47
63
  | Attribute | Elements | Description |
48
64
  | :--- | :--- | :--- |
49
- | `data-ln-form` | `<form>` | Initializes the coordinator. Evaluates initial button states. |
50
- | `data-ln-form-auto` | `<form>` | Automatically submits the form on any user value change. |
51
- | `data-ln-form-debounce="ms"` | `<form>` | Debounce duration in milliseconds before auto-submitting. |
65
+ | `data-ln-form` | `<form>` | Initializes the coordinator. |
66
+ | `data-ln-form-action-edit` | `<form>` | Opt-in RESTful action routing. See below. |
67
+ | `data-ln-form-action-method="PUT"` | `<form>` | Override verb for `_method` (default `PUT`). Requires `data-ln-form-action-edit`. |
68
+ | `data-ln-form-scope` | `<form>` | Opt-in local-first write path. Empty = nearest ancestor `[data-ln-data-coordinator]`. Named = explicit coordinator override. Intercepts submit; incompatible with native/ajax submit on the same form. |
52
69
 
53
70
  ### JS API
54
71
 
55
- Access the coordinator instance directly via the `lnForm` property on the form element:
72
+ Access the instance directly via the `lnForm` property on the form
73
+ element:
56
74
 
57
75
  ```javascript
58
76
  const form = document.getElementById('user-form');
59
77
 
60
- // 1. Bulk populate fields by name (fires synthetic input/change events)
78
+ // Bulk populate fields by name (fires synthetic input/change events)
61
79
  form.lnForm.fill({ username: 'dalibor', role: 'admin' });
62
80
 
63
- // 2. Force-validate all fields and trigger submission if clean
64
- form.lnForm.submit();
65
-
66
- // 3. Clear all fields, reset validity states, and re-enable the fresh guard
67
- form.lnForm.reset();
68
-
69
- // 4. Check if all data-ln-validate fields are valid (Boolean getter)
70
- if (form.lnForm.isValid) { ... }
71
-
72
- // 5. Clean up listeners and destroy the instance
81
+ // Clean up listeners and destroy the instance
73
82
  form.lnForm.destroy();
74
83
  ```
75
84
 
76
85
  ---
77
86
 
78
- ## ⚡ DOM Events
87
+ ## 4. DOM Events
79
88
 
80
89
  ### Emitted
81
90
 
82
91
  | Event | Bubbles | Payload | Description |
83
92
  | :--- | :--- | :--- | :--- |
84
- | `ln-form:submit` | Yes | `{ data: Object }` | Dispatched with serialized form key-values on valid submission. |
85
- | `ln-form:reset-complete` | Yes | `{ target: HTMLElement }` | Dispatched after a complete reactive reset cycle. |
86
93
  | `ln-form:destroyed` | Yes | `{ target: HTMLElement }` | Dispatched when the coordinator is torn down. |
87
94
 
88
95
  ### Received
89
96
 
90
97
  | Event | Payload | Description |
91
98
  | :--- | :--- | :--- |
92
- | `ln-form:fill` | `{ key: value }` | Triggers form population. (Prefer direct `form.lnForm.fill()` API). |
93
- | `ln-form:reset` | None | Triggers form reset. (Prefer direct `form.lnForm.reset()` API). |
99
+ | `ln-fill` | `record \| null` | Canonical fan-out fill. `detail` → `this.fill(detail)` + apply action mode; `null` → native `form.reset()`. Guarded: only handled when `e.target === self.dom`. |
100
+
101
+ ---
102
+
103
+ ## 5. RESTful action routing (create vs. edit)
104
+
105
+ For Laravel REST backends, `ln-form` can rewrite `form.action` and inject
106
+ a hidden `_method` input driven off the fill record — no coordinator JS,
107
+ no second click listener.
108
+
109
+ **Opt-in:** add `data-ln-form-action-edit` to the `<form>`. Forms without
110
+ this attribute are completely inert — this feature does not exist for
111
+ them.
112
+
113
+ ### Attributes
114
+
115
+ | Attribute | On | Description |
116
+ | :--- | :--- | :--- |
117
+ | `data-ln-form-action-edit` | `<form>` | Opt-in. Empty value = RESTful default (`baseAction + '/' + id`). Non-empty value = template with `:id` placeholder. |
118
+ | `data-ln-form-action-edit="/path/:id"` | `<form>` | Template variant — `:id` is replaced with `encodeURIComponent(record.id)`. |
119
+ | `data-ln-form-action-method="PUT"` | `<form>` | HTTP verb written into `_method` on edit. Default: `PUT`. |
120
+
121
+ > The `<input name="_method">` is auto-ensured — do not author it
122
+ > manually. `ln-form` creates it on first fill if absent, or reuses the
123
+ > existing one.
124
+
125
+ ### Behavior
126
+
127
+ | Fill state | `form.action` | `<input name="_method">` |
128
+ | :--- | :--- | :--- |
129
+ | Edit (record with `id`) | Rewritten to edit URL | `PUT` (or custom verb) |
130
+ | New (`null` detail) | Restored to base action | `''` (empty — Laravel ignores) |
131
+
132
+ ### Examples
133
+
134
+ ```html
135
+ <!-- Minimal: baseAction + '/' + id -->
136
+ <form data-ln-form action="/packages" data-ln-form-action-edit>
137
+
138
+ <!-- Custom template -->
139
+ <form data-ln-form action="/packages" data-ln-form-action-edit="/packages/:id">
140
+
141
+ <!-- Custom verb -->
142
+ <form data-ln-form action="/packages"
143
+ data-ln-form-action-edit="/packages/:id"
144
+ data-ln-form-action-method="PATCH">
145
+ ```
146
+
147
+ > [!NOTE]
148
+ > This feature only rewrites `action`/`_method`. The actual HTTP request
149
+ > (native submit or ajax) is out of scope for `ln-form`.
150
+
151
+ ---
152
+
153
+ ## 6. What ln-form does NOT do
154
+
155
+ - **No transport.** It does not make XHR/fetch requests. Submit is
156
+ native HTML; ajax interception (if desired) belongs to a separate
157
+ component that listens to the native `submit` event.
158
+ - **No serialization, ever.** There is no `serializeForm` call inside
159
+ `ln-form`, no `ln-form:submit-record` event, no JSON payload — scoped
160
+ forms are serialized by the claiming `ln-data-coordinator`, not by
161
+ `ln-form`.
162
+ - **No validation orchestration, no submit listener at all.** `ln-form`
163
+ never dispatches `ln-validate:request-validate`, never calls
164
+ `preventDefault()`, and never touches `novalidate` — all of that is
165
+ entirely [`ln-validate`](../ln-validate/README.md)'s job (see its
166
+ README §Philosophy). Claiming a valid submit for the write pipeline
167
+ (scoped forms only) is `ln-data-coordinator`'s job (native `submit`,
168
+ bubble phase, its own `preventDefault()`) — `ln-form` plays no role in
169
+ that decision either.
94
170
 
95
171
  ---
96
172
 
97
- ## ⚠️ Common Pitfalls
173
+ ## 5b. Local-first write routing (`data-ln-form-scope`)
174
+
175
+ A form carrying `data-ln-form-scope` becomes the universal write entry
176
+ point for local-first/SPA pages. The `submit` event is intercepted at
177
+ three possible rungs, and whichever rung claims it decides the archetype:
178
+
179
+ 1. **Nobody** — native browser submit to `action` (+ `_method`), SSR.
180
+ 2. **`ln-ajax`** — fetch to `action`, page stays put (progressive
181
+ enhancement). `ln-ajax` explicitly skips forms carrying
182
+ `data-ln-form-scope` (see the `ln-ajax` README).
183
+ 3. **`ln-data-coordinator`** — a form with `data-ln-form-scope` has its
184
+ valid submit left native; `ln-form` never intercepts it beyond the
185
+ validation gate (§7 below). The nearest ancestor
186
+ `[data-ln-data-coordinator]` (or the named coordinator, if
187
+ `data-ln-form-scope="name"`) listens for the native `submit` on
188
+ `document` (bubble phase), claims it with `preventDefault()` once its
189
+ own scope/containment matches, serializes the form itself, and routes
190
+ it through the store → queue → connector write pipeline. See the
191
+ `ln-data-coordinator` README for the intake contract.
192
+
193
+ `ln-validate`'s submit gate runs on every method — GET included, exactly
194
+ like the native browser validation it replaces. A search form nested
195
+ inside a coordinator with invalid `data-ln-validate` fields is blocked
196
+ the same as any other form; a form with no `data-ln-validate` fields has
197
+ no gate at all. `ln-data-coordinator` reads the effective method
198
+ (`_method` input if present and non-empty, else the form's `method`
199
+ attribute) independently, purely to decide whether to claim the native
200
+ submit for the write pipeline (`POST` → create, `PUT`/`PATCH` → update) —
201
+ a `GET` form is never claimed, regardless of validity. `ln-form` itself
202
+ stays coordinator-blind and validation-blind: it never serializes, never
203
+ dispatches a custom event, and never listens for `submit`.
204
+
205
+ ---
206
+
207
+ ## 7. Common Pitfalls
208
+
209
+ - **Setting `input.value` directly:** Doing `input.value = 'new'` is
210
+ silent in the DOM. Neither validation nor layout systems will detect
211
+ the change. **Always** use `form.lnForm.fill()` or manually dispatch an
212
+ `input`/`change` event.
213
+ - **Expecting a submit event:** `ln-form` never dispatches anything on
214
+ submit — there is no `ln-form:submit` and no `ln-form:submit-record`
215
+ either. Listen to the form's native `submit` event, or the resulting
216
+ `ln-data-store:created`/`ln-data-store:updated` outcome, instead.
217
+
218
+ ---
219
+
220
+ ## 8. Integration & Source Files
221
+
222
+ - **Unified Bundle**: Loaded automatically with the main bundle:
223
+ ```html
224
+ <script src="dist/ln-ashlar.iife.js" defer></script>
225
+ ```
226
+ - **Standalone IIFE**: For lightweight pages, load the standalone,
227
+ self-registering IIFE version:
228
+ ```html
229
+ <script src="js/ln-form/ln-form.js" defer></script>
230
+ ```
231
+ - **Active Source (ESM)**: Development source is located at
232
+ [js/ln-form/src/ln-form.js](file:///c:/laragon/www/ln-ashlar/js/ln-form/src/ln-form.js).
233
+
234
+ ---
235
+
236
+ ## 🔧 Internals
237
+
238
+ Source: `js/ln-form/ln-form.js`. Instance state is minimal: `dom` (the form) and `_baseAction` (the `action` attribute captured once at init, restored on "new" mode). No validation index, no debounce, no submit-button bookkeeping — `ln-form` does not orchestrate submission.
239
+
240
+ ### `fill(data)`
241
+
242
+ Iterates `form.elements` writing by `name`: checkboxes get `.checked = Boolean(value)`, radios match `el.value === String(value)`, `select-multiple` sets `options[n].selected`, everything else sets `.value`. Each written element then dispatches exactly one synthetic event — `change` for `SELECT`/checkbox/radio, `input` otherwise (the `isChangeBased` discriminator). This mirrors the same discriminator `ln-validate` and `ln-autoresize` use for their own listener registration, so every field fires the event those consumers actually listen for — no double fires, no missed reactions.
243
+
244
+ ### `ln-fill` handling
245
+
246
+ Guarded to `e.target === self.dom` (ignores bubbled `ln-fill` from nested `[data-ln-fillable]` children). A record calls `fill()` then `_applyActionMode(record)`; `null` calls `form.reset()` — the native `reset` event that fires from that call is what actually restores the base action (see below), not the `ln-fill` handler directly.
247
+
248
+ ### Reset routing
249
+
250
+ The native `reset` event — whether from `form.reset()` above, a `<button type="reset">`, or any other trigger — always runs `_applyActionMode(null)`, restoring `_baseAction` and clearing `_method`. There is no synthetic input/change replay on reset and no `ln-form:reset-complete` event.
251
+
252
+ ### Action-mode guard
253
+
254
+ `_applyActionMode` exits immediately on forms without `data-ln-form-action-edit` — unrelated forms are untouched by the reset/fill listeners' side effects.
255
+
256
+ ### Relation to ln-validate
257
+
258
+ Independent siblings, no imports between them. `ln-validate` injects `novalidate` the moment its first field initializes (authors never write it by hand); a form with zero `data-ln-validate` fields keeps native validation as the default. `ln-validate` has its own separate `reset` listener (clears field error classes / `_touched` state) — unrelated to `ln-form`'s reset listener, which only handles action/`_method`.
259
+
260
+ ---
98
261
 
99
- - **Setting `input.value` directly:** Doing `input.value = 'new'` is silent in the DOM. Neither validation nor layout systems will detect the change. **Always** use `form.lnForm.fill()` or manually dispatch an `input` or `change` event.
100
- - **Relying on Native Form Resets:** Clicking a `<button type="reset">` only reverts DOM attributes. It does not trigger synthetic events, leaving textareas at expanded heights and custom controls out of sync. Use `form.lnForm.reset()` instead.
101
- - **Debounced fill on auto-submit forms:** Calling `fill()` on an auto-submit form will trigger an automatic submission after the debounce timeout.
262
+ ## Related
263
+ - **[`ln-validate`](../ln-validate/README.md)** — Field-level validation and error display.
264
+ - **[`ln-fill`](../ln-fill/README.md)** — Fan-out fill event source.
@@ -1 +1 @@
1
- (function(){"use strict";function y(s,t,u){s.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:u||{}}))}function E(s,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){E(s,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}s()}function v(s,t,u,a){if(s.nodeType!==1)return;const o=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",r=Array.from(s.querySelectorAll(o));s.matches&&s.matches(o)&&r.push(s);for(const e of r)e[u]||(e[u]=new a(e))}function S(s){const t={},u=s.elements;for(let a=0;a<u.length;a++){const i=u[a];if(!(!i.name||i.disabled||i.type==="file"||i.type==="submit"||i.type==="button"))if(i.type==="checkbox")t[i.name]||(t[i.name]=[]),i.checked&&t[i.name].push(i.value);else if(i.type==="radio")i.checked&&(t[i.name]=i.value);else if(i.type==="select-multiple"){t[i.name]=[];for(let o=0;o<i.options.length;o++)i.options[o].selected&&t[i.name].push(i.options[o].value)}else t[i.name]=i.value}return t}function w(s,t){const u=s.elements,a=[];for(let i=0;i<u.length;i++){const o=u[i];if(!o.name||!(o.name in t)||o.type==="file"||o.type==="submit"||o.type==="button")continue;const r=t[o.name];if(o.type==="checkbox")o.checked=Array.isArray(r)?r.indexOf(o.value)!==-1:!!r,a.push(o);else if(o.type==="radio")o.checked=o.value===String(r),a.push(o);else if(o.type==="select-multiple"){if(Array.isArray(r))for(let e=0;e<o.options.length;e++)o.options[e].selected=r.indexOf(o.options[e].value)!==-1;a.push(o)}else o.value=r,a.push(o)}return a}function x(s,t,u,a,i={}){const o=i.extraAttributes||[],r=i.onAttributeChange||null,e=i.onInit||null;function n(l){const d=l||document.body;v(d,s,t,u),e&&e(d)}return E(function(){const l=new MutationObserver(function(f){for(let h=0;h<f.length;h++){const c=f[h];if(c.type==="childList"){for(let p=0;p<c.addedNodes.length;p++){const m=c.addedNodes[p];m.nodeType===1&&(v(m,s,t,u),e&&e(m))}for(let p=0;p<c.removedNodes.length;p++){const m=c.removedNodes[p];if(m.nodeType===1){const L=s.indexOf("[")!==-1||s.indexOf(".")!==-1||s.indexOf("#")!==-1?s:"["+s+"]",b=Array.from(m.querySelectorAll(L));m.matches&&m.matches(L)&&b.push(m);for(let g=0;g<b.length;g++){const T=b[g];if(!document.contains(T)){const _=T[t];_&&typeof _.destroy=="function"&&_.destroy()}}}}}else c.type==="attributes"&&(r&&c.target[t]?r(c.target,c.attributeName):(v(c.target,s,t,u),e&&e(c.target)))}});let d=[];if(s.indexOf("[")!==-1){const f=/\[([\w-]+)/g;let h;for(;(h=f.exec(s))!==null;)d.push(h[1])}else d.push(s);l.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:d.concat(o)})},a),window[t]=n,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){n(document.body)}):n(document.body),n}const A={};function C(s,t){A[s]=t}function O(s){return A[s]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=C,window.lnCore.getDataMapper=O),(function(){const s="data-ln-form",t="lnForm",u="data-ln-form-auto",a="data-ln-form-debounce",i="data-ln-validate",o="lnValidate";if(window[t]!==void 0)return;function r(e){this.dom=e,this._debounceTimer=null;const n=this;if(this._onValid=function(){n._updateSubmitButton()},this._onInvalid=function(){n._updateSubmitButton()},this._onSubmit=function(l){l.preventDefault(),n.submit()},this._onFill=function(l){l.detail&&n.fill(l.detail)},this._onFormReset=function(){n.reset()},this._onNativeReset=function(){setTimeout(function(){n._resetValidation()},0)},e.addEventListener("ln-validate:valid",this._onValid),e.addEventListener("ln-validate:invalid",this._onInvalid),e.addEventListener("submit",this._onSubmit),e.addEventListener("ln-form:fill",this._onFill),e.addEventListener("ln-form:reset",this._onFormReset),e.addEventListener("reset",this._onNativeReset),this._onAutoInput=null,e.hasAttribute(u)){const l=parseInt(e.getAttribute(a))||0;this._onAutoInput=function(){l>0?(clearTimeout(n._debounceTimer),n._debounceTimer=setTimeout(function(){n.submit()},l)):n.submit()},e.addEventListener("input",this._onAutoInput),e.addEventListener("change",this._onAutoInput)}return this._updateSubmitButton(),this}r.prototype._updateSubmitButton=function(){const e=this.dom.querySelectorAll('button[type="submit"], input[type="submit"]');if(!e.length)return;const n=this.dom.querySelectorAll("["+i+"]");let l=!1;if(n.length>0){let d=!1,f=!1;for(let h=0;h<n.length;h++){const c=n[h][o];c&&c._touched&&(d=!0),n[h].checkValidity()||(f=!0)}l=f||!d}for(let d=0;d<e.length;d++)e[d].disabled=l},r.prototype.fill=function(e){const n=w(this.dom,e);for(let l=0;l<n.length;l++){const d=n[l],f=d.tagName==="SELECT"||d.type==="checkbox"||d.type==="radio";d.dispatchEvent(new Event(f?"change":"input",{bubbles:!0}))}},r.prototype.submit=function(){const e=this.dom.querySelectorAll("["+i+"]");let n=!0;for(let d=0;d<e.length;d++){const f=e[d][o];f&&(f.validate()||(n=!1))}if(!n)return;const l=S(this.dom);y(this.dom,"ln-form:submit",{data:l})},r.prototype.reset=function(){this.dom.reset();const e=this.dom.querySelectorAll("input, textarea, select");for(let n=0;n<e.length;n++){const l=e[n],d=l.tagName==="SELECT"||l.type==="checkbox"||l.type==="radio";l.dispatchEvent(new Event(d?"change":"input",{bubbles:!0}))}this._resetValidation(),y(this.dom,"ln-form:reset-complete",{target:this.dom})},r.prototype._resetValidation=function(){const e=this.dom.querySelectorAll("["+i+"]");for(let n=0;n<e.length;n++){const l=e[n][o];l&&l.reset()}this._updateSubmitButton()},Object.defineProperty(r.prototype,"isValid",{get:function(){const e=this.dom.querySelectorAll("["+i+"]");for(let n=0;n<e.length;n++)if(!e[n].checkValidity())return!1;return!0}}),r.prototype.destroy=function(){this.dom[t]&&(this.dom.removeEventListener("ln-validate:valid",this._onValid),this.dom.removeEventListener("ln-validate:invalid",this._onInvalid),this.dom.removeEventListener("submit",this._onSubmit),this.dom.removeEventListener("ln-form:fill",this._onFill),this.dom.removeEventListener("ln-form:reset",this._onFormReset),this.dom.removeEventListener("reset",this._onNativeReset),this._onAutoInput&&(this.dom.removeEventListener("input",this._onAutoInput),this.dom.removeEventListener("change",this._onAutoInput)),clearTimeout(this._debounceTimer),y(this.dom,"ln-form:destroyed",{target:this.dom}),delete this.dom[t])},x(s,t,r,"ln-form")})()})();
1
+ (function(){"use strict";if(typeof window<"u"){const t=console.warn;console.warn=function(...e){typeof e[0]=="string"&&(e[0].startsWith("[ln-")||e[0].startsWith("[lnCore"))&&!(document.documentElement.hasAttribute("data-ln-debug")||document.body&&document.body.hasAttribute("data-ln-debug"))||t.apply(console,e)}}const y={};function M(t,e){y[t]||(y[t]=document.querySelector('[data-ln-template="'+t+'"]'));const s=y[t];return s?s.content.cloneNode(!0):(console.warn("["+(e||"ln-core")+'] Template "'+t+'" not found'),null)}function D(t,e,s){t.dispatchEvent(new CustomEvent(e,{bubbles:!0,detail:s||{}}))}function v(t,e){if(!t||!e)return t;const s=t.querySelectorAll("[data-ln-field]");for(let n=0;n<s.length;n++){const i=s[n],l=i.getAttribute("data-ln-field");e[l]!=null&&(i.textContent=e[l])}const d=t.querySelectorAll("[data-ln-attr]");for(let n=0;n<d.length;n++){const i=d[n],l=i.getAttribute("data-ln-attr").split(",");for(let r=0;r<l.length;r++){const u=l[r].trim().split(":");if(u.length!==2)continue;const a=u[0].trim(),f=u[1].trim();e[f]!=null&&i.setAttribute(a,e[f])}}const c=t.querySelectorAll("[data-ln-show]");for(let n=0;n<c.length;n++){const i=c[n],l=i.getAttribute("data-ln-show");l in e&&i.classList.toggle("hidden",!e[l])}const o=t.querySelectorAll("[data-ln-class]");for(let n=0;n<o.length;n++){const i=o[n],l=i.getAttribute("data-ln-class").split(",");for(let r=0;r<l.length;r++){const u=l[r].trim().split(":");if(u.length!==2)continue;const a=u[0].trim(),f=u[1].trim();f in e&&i.classList.toggle(a,!!e[f])}}return t}function q(t,e){t.matches&&t.matches("[data-ln-form], [data-ln-fillable]")&&t.dispatchEvent(new CustomEvent("ln-fill",{detail:e??null,bubbles:!0}));const s=t.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let d=0;d<s.length;d++)s[d].dispatchEvent(new CustomEvent("ln-fill",{detail:e??null,bubbles:!0}));return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(t){if(!(!t.target.matches||!t.target.matches("[data-ln-fillable]")))if(t.detail)v(t.target,t.detail);else{const e=t.target.querySelectorAll("[data-ln-field]");for(let s=0;s<e.length;s++)e[s].textContent=""}})));function x(t,e){if(!t||!e)return t;const s=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(;s.nextNode();){const o=s.currentNode;o.textContent.indexOf("{{")!==-1&&(o.textContent=o.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(n,i){return e[i]!==void 0?e[i]:""}))}const d=function(o,n){return e[n]!==void 0?e[n]:""},c=Array.from(t.querySelectorAll("*"));t.nodeType===1&&c.push(t);for(let o=0;o<c.length;o++){const n=c[o],i=n.attributes;for(let l=0;l<i.length;l++){const r=i[l];r.value.indexOf("{{")!==-1&&n.setAttribute(r.name,r.value.replace(/\{\{\s*(\w+)\s*\}\}/g,d))}}return t}function I(t,e,s,d,c,o){const n={};for(let l=0;l<t.children.length;l++){const r=t.children[l],u=r.getAttribute("data-ln-key");u&&(n[u]=r)}const i=document.createDocumentFragment();for(let l=0;l<e.length;l++){const r=e[l],u=String(d(r));let a=n[u];if(a)c(a,r,l);else{const f=M(s,o);if(!f||(x(f,r),a=f.firstElementChild,!a))continue;a.setAttribute("data-ln-key",u),c(a,r,l)}i.appendChild(a)}t.textContent="",t.appendChild(i)}function _(t,e){if(!document.body){document.addEventListener("DOMContentLoaded",function(){_(t,e)}),console.warn("["+e+'] Script loaded before <body> — add "defer" to your <script> tag');return}t()}function g(t,e,s,d){if(t.nodeType!==1)return;const o=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]",n=Array.from(t.querySelectorAll(o));t.matches&&t.matches(o)&&n.push(t);for(const i of n)i[s]||(i[s]=new d(i))}function N(t){if(typeof t!="string")return!!t;const e=t.trim().toLowerCase();return e!=="false"&&e!=="0"&&e!==""&&e!=="off"&&e!=="no"}function F(t,e){const s=t.elements,d=[],c={};for(let o=0;o<s.length;o++){const n=s[o];n.name&&n.type==="checkbox"&&(c[n.name]=(c[n.name]||0)+1)}for(let o=0;o<s.length;o++){const n=s[o];if(n.type==="file"||n.type==="submit"||n.type==="button")continue;const i=n.getAttribute("data-ln-fill-as")||n.name;if(!i||!(i in e))continue;const l=e[i];if(n.type==="checkbox"){if(Array.isArray(l))n.checked=l.indexOf(n.value)!==-1;else if(c[n.name]>1){const r=String(l).split(",").map(function(u){return u.trim()});n.checked=r.indexOf(n.value)!==-1}else n.checked=N(l);d.push(n)}else if(n.type==="radio")n.checked=n.value===String(l),d.push(n);else if(n.type==="select-multiple"){if(Array.isArray(l))for(let r=0;r<n.options.length;r++)n.options[r].selected=l.indexOf(n.options[r].value)!==-1;d.push(n)}else n.value=l,d.push(n)}return d}function R(t,e,s,d,c={}){const o=c.extraAttributes||[],n=c.onAttributeChange||null,i=c.onInit||null;function l(r){const u=r||document.body;g(u,t,e,s),i&&i(u)}return _(function(){const r=new MutationObserver(function(a){for(let f=0;f<a.length;f++){const h=a[f];if(h.type==="childList"){for(let m=0;m<h.addedNodes.length;m++){const p=h.addedNodes[m];p.nodeType===1&&(g(p,t,e,s),i&&i(p))}for(let m=0;m<h.removedNodes.length;m++){const p=h.removedNodes[m];if(p.nodeType===1){const O=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",b=Array.from(p.querySelectorAll(O));p.matches&&p.matches(O)&&b.push(p);for(let C=0;C<b.length;C++){const S=b[C];if(!document.contains(S)){const A=S[e];A&&typeof A.destroy=="function"&&A.destroy()}}}}}else h.type==="attributes"&&(n&&h.target[e]?n(h.target,h.attributeName):(g(h.target,t,e,s),i&&i(h.target)))}});let u=[];if(t.indexOf("[")!==-1){const a=/\[([\w-]+)/g;let f;for(;(f=a.exec(t))!==null;)u.push(f[1])}else u.push(t);r.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:u.concat(o)})},d),window[e]=l,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){l(document.body)}):l(document.body),l}const L={};function j(t,e){L[t]=e}function B(t){return L[t]||{ingress:e=>e,egress:e=>e}}const E={};function k(t,e){if(!t||typeof e!="object")return;const s=t.toLowerCase().split("-")[0];E[s]=e}function W(t){if(!t)return null;const e=t.toLowerCase().split("-")[0];return E[e]||null}k("mk",{monthsLong:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],monthsShort:["јан","фев","мар","апр","мај","јун","јул","авг","септ","окт","ноем","дек"],daysLong:["недела","понеделник","вторник","среда","четврток","петок","сабота"],daysShort:["нед","пон","вт","ср","чет","пет","саб"]}),typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=j,window.lnCore.getDataMapper=B,window.lnCore.registerLocaleFallback=k,window.lnCore.getLocaleFallback=W,window.lnCore.fillTemplate=x,window.lnCore.fill=v,window.lnCore.lnFill=q,window.lnCore.renderList=I);function T(t){return(t||"").replace(/^#/,"")}function w(t){const e=t===void 0?location.hash:t,s={},d=T(e);if(!d)return s;const c=d.split("&");for(let o=0;o<c.length;o++){const n=c[o];if(!n)continue;const i=n.indexOf(":"),l=i>-1?n.slice(0,i):n,r=i>-1?n.slice(i+1):"";if(l)try{s[l]=decodeURIComponent(r)}catch{s[l]=r}}return s}function U(t){if(!t)return null;const e=w();return t in e?e[t]:null}function K(t,e){if(!t)return;const s=w();e==null?delete s[t]:s[t]=String(e);const c=Object.keys(s).map(function(o){const n=s[o];return n===""?o:o+":"+encodeURIComponent(n)}).join("&");T(location.hash)!==c&&(location.hash=c)}function G(t){return t.button===1||t.ctrlKey||t.metaKey||t.shiftKey?!1:(t.preventDefault(),!0)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=w,window.lnCore.hashGet=U,window.lnCore.hashSet=K,window.lnCore.hashLinkClick=G),(function(){const t="data-ln-form",e="lnForm",s="data-ln-form-action-edit",d="data-ln-form-action-method";if(window[e]!==void 0)return;function c(o){this.dom=o,this._baseAction=o.getAttribute("action")||"";const n=this;return this._onLnFill=function(i){i.target===n.dom&&(i.detail?(n.fill(i.detail),n._applyActionMode(i.detail)):n.dom.reset())},this._onReset=function(){n._applyActionMode(null)},o.addEventListener("ln-fill",this._onLnFill),o.addEventListener("reset",this._onReset),this}c.prototype.fill=function(o){const n=F(this.dom,o);for(let i=0;i<n.length;i++){const l=n[i],r=l.tagName==="SELECT"||l.type==="checkbox"||l.type==="radio";l.dispatchEvent(new Event(r?"change":"input",{bubbles:!0}))}},c.prototype._ensureMethodInput=function(){let o=this.dom.querySelector('input[name="_method"]');return o||(o=document.createElement("input"),o.type="hidden",o.name="_method",o.value="",this.dom.appendChild(o)),o},c.prototype._applyActionMode=function(o){if(!this.dom.hasAttribute(s))return;const n=o&&o.id!=null&&o.id!==""?o.id:null,i=this._ensureMethodInput();if(n!==null){const l=this.dom.getAttribute(s);l?this.dom.setAttribute("action",l.replace(":id",encodeURIComponent(n))):this.dom.setAttribute("action",this._baseAction.replace(/\/$/,"")+"/"+encodeURIComponent(n)),i.value=this.dom.getAttribute(d)||"PUT"}else this.dom.setAttribute("action",this._baseAction),i.value=""},c.prototype.destroy=function(){this.dom[e]&&(this.dom.removeEventListener("ln-fill",this._onLnFill),this.dom.removeEventListener("reset",this._onReset),D(this.dom,"ln-form:destroyed",{target:this.dom}),delete this.dom[e])},R(t,e,c,"ln-form")})()})();