@livenetworks/ashlar 1.5.1 → 1.6.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 (217) 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 +165 -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 +82 -42
  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 +92 -2
  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 -56
  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 -25
  173. package/scss/components/_form.scss +7 -0
  174. package/scss/components/_ln-table.scss +13 -3
  175. package/scss/components/_sort.scss +10 -0
  176. package/scss/components/_table.scss +36 -23
  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 +11 -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 +3 -5
  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 +2 -0
  198. package/scss/config/mixins/_ln-table.scss +41 -2
  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 +85 -60
  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 +27 -9
  209. package/scss/ln-ashlar.scss +7 -1
  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 -1087
  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 -156
@@ -0,0 +1,18 @@
1
+ @use '../../scss/config/mixins' as *;
2
+
3
+ [data-ln-debug] {
4
+ // 1. Tabs Configuration Check: [data-ln-tabs] must have an id or data-ln-tabs-key
5
+ [data-ln-tabs]:not([id]):not([data-ln-tabs-key]) {
6
+ @include dev-dom-error("[data-ln-tabs] must have an 'id' or 'data-ln-tabs-key' for state tracking.");
7
+ }
8
+
9
+ // 2. Tab Trigger Type: triggers inside forms must be explicitly type="button" to prevent submit events
10
+ form [data-ln-tabs-for]:not([type="button"]) {
11
+ @include dev-inline-error("tab trigger within form must have type='button'");
12
+ }
13
+
14
+ // 3. Tab Trigger Nesting Check: [data-ln-tabs-for] must be nested inside a [data-ln-tabs] parent container
15
+ [data-ln-tabs-for]:not([data-ln-tabs] *) {
16
+ @include dev-inline-error("[data-ln-tabs-for] is orphaned (not inside a [data-ln-tabs] container)");
17
+ }
18
+ }
@@ -1 +1 @@
1
- (function(){"use strict";function A(s,n,o){s.dispatchEvent(new CustomEvent(n,{bubbles:!0,detail:o||{}}))}function v(s,n){if(!document.body){document.addEventListener("DOMContentLoaded",function(){v(s,n)}),console.warn("["+n+'] Script loaded before <body> — add "defer" to your <script> tag');return}s()}function b(s,n,o,d){if(s.nodeType!==1)return;const p=n.indexOf("[")!==-1||n.indexOf(".")!==-1||n.indexOf("#")!==-1?n:"["+n+"]",e=Array.from(s.querySelectorAll(p));s.matches&&s.matches(p)&&e.push(s);for(const t of e)t[o]||(t[o]=new d(t))}function O(s,n,o,d,m={}){const p=m.extraAttributes||[],e=m.onAttributeChange||null,t=m.onInit||null;function i(a){const r=a||document.body;b(r,s,n,o),t&&t(r)}return v(function(){const a=new MutationObserver(function(f){for(let c=0;c<f.length;c++){const l=f[c];if(l.type==="childList"){for(let h=0;h<l.addedNodes.length;h++){const u=l.addedNodes[h];u.nodeType===1&&(b(u,s,n,o),t&&t(u))}for(let h=0;h<l.removedNodes.length;h++){const u=l.removedNodes[h];if(u.nodeType===1){const E=s.indexOf("[")!==-1||s.indexOf(".")!==-1||s.indexOf("#")!==-1?s:"["+s+"]",y=Array.from(u.querySelectorAll(E));u.matches&&u.matches(E)&&y.push(u);for(let g=0;g<y.length;g++){const L=y[g];if(!document.contains(L)){const w=L[n];w&&typeof w.destroy=="function"&&w.destroy()}}}}}else l.type==="attributes"&&(e&&l.target[n]?e(l.target,l.attributeName):(b(l.target,s,n,o),t&&t(l.target)))}});let r=[];if(s.indexOf("[")!==-1){const f=/\[([\w-]+)/g;let c;for(;(c=f.exec(s))!==null;)r.push(c[1])}else r.push(s);a.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:r.concat(p)})},d),window[n]=i,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){i(document.body)}):i(document.body),i}const C={};function T(s,n){C[s]=n}function _(s){return C[s]||{ingress:n=>n,egress:n=>n}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=T,window.lnCore.getDataMapper=_);const K="ln:";function S(){return location.pathname.replace(/\/+$/,"").toLowerCase()||"/"}function x(s,n){const o=n.getAttribute("data-ln-persist"),d=o!==null&&o!==""?o:n.id;return d?K+s+":"+S()+":"+d:(console.warn('[ln-persist] Element requires id or data-ln-persist="key"',n),null)}function k(s,n){const o=x(s,n);if(!o)return null;try{const d=localStorage.getItem(o);return d!==null?JSON.parse(d):null}catch{return null}}function M(s,n,o){const d=x(s,n);if(d)try{localStorage.setItem(d,JSON.stringify(o))}catch{}}(function(){const s="data-ln-tabs",n="lnTabs";if(window[n]!==void 0&&window[n]!==null)return;function o(){const e=(location.hash||"").replace("#",""),t={};if(!e)return t;for(const i of e.split("&")){const a=i.indexOf(":");a>0&&(t[i.slice(0,a)]=i.slice(a+1))}return t}function d(e,t){const i=(e.getAttribute("data-ln-tab")||"").toLowerCase().trim();if(i)return i;if(e.tagName!=="A")return"";const a=e.getAttribute("href")||"";if(!a.startsWith("#"))return"";const r=a.slice(1);if(!r)return"";const f=r.split("&");if(t)for(const h of f){const u=h.indexOf(":");if(u>0&&h.slice(0,u).toLowerCase().trim()===t)return h.slice(u+1).toLowerCase().trim()}const c=f[f.length-1]||"",l=c.indexOf(":");return(l>0?c.slice(l+1):c).toLowerCase().trim()}function m(e){return this.dom=e,p.call(this),this}function p(){this.tabs=Array.from(this.dom.querySelectorAll("[data-ln-tab]")),this.panels=Array.from(this.dom.querySelectorAll("[data-ln-panel]")),this.nsKey=(this.dom.getAttribute("data-ln-tabs-key")||this.dom.id||"").toLowerCase().trim(),this.hashEnabled=!!this.nsKey,this.mapTabs={},this.mapPanels={};for(const t of this.tabs){const i=d(t,this.nsKey);i?this.mapTabs[i]=t:console.warn('[ln-tabs] Trigger has no resolvable key — needs `data-ln-tab="key"` or `<a href="#…">`.',t)}for(const t of this.panels){const i=(t.getAttribute("data-ln-panel")||"").toLowerCase().trim();i&&(this.mapPanels[i]=t)}this.defaultKey=(this.dom.getAttribute("data-ln-tabs-default")||"").toLowerCase().trim()||Object.keys(this.mapTabs)[0]||"",this.autoFocus=(this.dom.getAttribute("data-ln-tabs-focus")||"true").toLowerCase()!=="false";const e=this;this._clickHandlers=[];for(const t of this.tabs){if(t[n+"Trigger"])continue;const i=function(a){if(a.ctrlKey||a.metaKey||a.button===1)return;const r=d(t,e.nsKey);if(r)if(t.tagName==="A"&&a.preventDefault(),e.hashEnabled){const f=o();f[e.nsKey]=r;const c=Object.keys(f).map(function(l){return l+":"+f[l]}).join("&");location.hash==="#"+c?e.dom.setAttribute("data-ln-tabs-active",r):location.hash=c}else e.dom.setAttribute("data-ln-tabs-active",r)};t.addEventListener("click",i),t[n+"Trigger"]=i,e._clickHandlers.push({el:t,handler:i})}if(this._hashHandler=function(){if(!e.hashEnabled)return;const t=o();e.dom.setAttribute("data-ln-tabs-active",e.nsKey in t?t[e.nsKey]:e.defaultKey)},this.hashEnabled)window.addEventListener("hashchange",this._hashHandler),this._hashHandler();else{let t=this.defaultKey;if(this.dom.hasAttribute("data-ln-persist")&&!this.hashEnabled){const i=k("tabs",this.dom);i!==null&&i in this.mapPanels&&(t=i)}this.dom.setAttribute("data-ln-tabs-active",t)}}m.prototype._applyActive=function(e){var t;(!e||!(e in this.mapPanels))&&(e=this.defaultKey);for(const i in this.mapTabs){const a=this.mapTabs[i];i===e?(a.setAttribute("data-active",""),a.setAttribute("aria-selected","true")):(a.removeAttribute("data-active"),a.setAttribute("aria-selected","false"))}for(const i in this.mapPanels){const a=this.mapPanels[i],r=i===e;a.classList.toggle("hidden",!r),a.setAttribute("aria-hidden",r?"false":"true")}if(this.autoFocus){const i=(t=this.mapPanels[e])==null?void 0:t.querySelector('input,button,select,textarea,[tabindex]:not([tabindex="-1"])');i&&setTimeout(()=>i.focus({preventScroll:!0}),0)}A(this.dom,"ln-tabs:change",{key:e,tab:this.mapTabs[e],panel:this.mapPanels[e]}),this.dom.hasAttribute("data-ln-persist")&&!this.hashEnabled&&M("tabs",this.dom,e)},m.prototype.destroy=function(){if(this.dom[n]){for(const{el:e,handler:t}of this._clickHandlers)e.removeEventListener("click",t),delete e[n+"Trigger"];this.hashEnabled&&window.removeEventListener("hashchange",this._hashHandler),A(this.dom,"ln-tabs:destroyed",{target:this.dom}),delete this.dom[n]}},O(s,n,m,"ln-tabs",{extraAttributes:["data-ln-tabs-active"],onAttributeChange:function(e){const t=e.getAttribute("data-ln-tabs-active");e[n]._applyActive(t)}})})()})();
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 g={};function P(t,e){g[t]||(g[t]=document.querySelector('[data-ln-template="'+t+'"]'));const o=g[t];return o?o.content.cloneNode(!0):(console.warn("["+(e||"ln-core")+'] Template "'+t+'" not found'),null)}function S(t,e,o){t.dispatchEvent(new CustomEvent(e,{bubbles:!0,detail:o||{}}))}function _(t,e){if(!t||!e)return t;const o=t.querySelectorAll("[data-ln-field]");for(let r=0;r<o.length;r++){const s=o[r],n=s.getAttribute("data-ln-field");e[n]!=null&&(s.textContent=e[n])}const a=t.querySelectorAll("[data-ln-attr]");for(let r=0;r<a.length;r++){const s=a[r],n=s.getAttribute("data-ln-attr").split(",");for(let l=0;l<n.length;l++){const c=n[l].trim().split(":");if(c.length!==2)continue;const f=c[0].trim(),d=c[1].trim();e[d]!=null&&s.setAttribute(f,e[d])}}const u=t.querySelectorAll("[data-ln-show]");for(let r=0;r<u.length;r++){const s=u[r],n=s.getAttribute("data-ln-show");n in e&&s.classList.toggle("hidden",!e[n])}const i=t.querySelectorAll("[data-ln-class]");for(let r=0;r<i.length;r++){const s=i[r],n=s.getAttribute("data-ln-class").split(",");for(let l=0;l<n.length;l++){const c=n[l].trim().split(":");if(c.length!==2)continue;const f=c[0].trim(),d=c[1].trim();d in e&&s.classList.toggle(f,!!e[d])}}return t}function R(t,e){t.matches&&t.matches("[data-ln-form], [data-ln-fillable]")&&t.dispatchEvent(new CustomEvent("ln-fill",{detail:e??null,bubbles:!0}));const o=t.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let a=0;a<o.length;a++)o[a].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)_(t.target,t.detail);else{const e=t.target.querySelectorAll("[data-ln-field]");for(let o=0;o<e.length;o++)e[o].textContent=""}})));function x(t,e){if(!t||!e)return t;const o=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(;o.nextNode();){const i=o.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(r,s){return e[s]!==void 0?e[s]:""}))}const a=function(i,r){return e[r]!==void 0?e[r]:""},u=Array.from(t.querySelectorAll("*"));t.nodeType===1&&u.push(t);for(let i=0;i<u.length;i++){const r=u[i],s=r.attributes;for(let n=0;n<s.length;n++){const l=s[n];l.value.indexOf("{{")!==-1&&r.setAttribute(l.name,l.value.replace(/\{\{\s*(\w+)\s*\}\}/g,a))}}return t}function j(t,e,o,a,u,i){const r={};for(let n=0;n<t.children.length;n++){const l=t.children[n],c=l.getAttribute("data-ln-key");c&&(r[c]=l)}const s=document.createDocumentFragment();for(let n=0;n<e.length;n++){const l=e[n],c=String(a(l));let f=r[c];if(f)u(f,l,n);else{const d=P(o,i);if(!d||(x(d,l),f=d.firstElementChild,!f))continue;f.setAttribute("data-ln-key",c),u(f,l,n)}s.appendChild(f)}t.textContent="",t.appendChild(s)}function k(t,e){if(!document.body){document.addEventListener("DOMContentLoaded",function(){k(t,e)}),console.warn("["+e+'] Script loaded before <body> — add "defer" to your <script> tag');return}t()}function w(t,e,o,a){if(t.nodeType!==1)return;const i=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]",r=Array.from(t.querySelectorAll(i));t.matches&&t.matches(i)&&r.push(t);for(const s of r)s[o]||(s[o]=new a(s))}function W(t,e,o,a,u={}){const i=u.extraAttributes||[],r=u.onAttributeChange||null,s=u.onInit||null;function n(l){const c=l||document.body;w(c,t,e,o),s&&s(c)}return k(function(){const l=new MutationObserver(function(f){for(let d=0;d<f.length;d++){const h=f[d];if(h.type==="childList"){for(let m=0;m<h.addedNodes.length;m++){const p=h.addedNodes[m];p.nodeType===1&&(w(p,t,e,o),s&&s(p))}for(let m=0;m<h.removedNodes.length;m++){const p=h.removedNodes[m];if(p.nodeType===1){const I=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",C=Array.from(p.querySelectorAll(I));p.matches&&p.matches(I)&&C.push(p);for(let v=0;v<C.length;v++){const M=C[v];if(!document.contains(M)){const L=M[e];L&&typeof L.destroy=="function"&&L.destroy()}}}}}else h.type==="attributes"&&(r&&h.target[e]?r(h.target,h.attributeName):(w(h.target,t,e,o),s&&s(h.target)))}});let c=[];if(t.indexOf("[")!==-1){const f=/\[([\w-]+)/g;let d;for(;(d=f.exec(t))!==null;)c.push(d[1])}else c.push(t);l.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:c.concat(i)})},a),window[e]=n,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){n(document.body)}):n(document.body),n}const E={};function H(t,e){E[t]=e}function B(t){return E[t]||{ingress:e=>e,egress:e=>e}}const T={};function q(t,e){if(!t||typeof e!="object")return;const o=t.toLowerCase().split("-")[0];T[o]=e}function U(t){if(!t)return null;const e=t.toLowerCase().split("-")[0];return T[e]||null}q("mk",{monthsLong:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],monthsShort:["јан","фев","мар","апр","мај","јун","јул","авг","септ","окт","ноем","дек"],daysLong:["недела","понеделник","вторник","среда","четврток","петок","сабота"],daysShort:["нед","пон","вт","ср","чет","пет","саб"]}),typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=H,window.lnCore.getDataMapper=B,window.lnCore.registerLocaleFallback=q,window.lnCore.getLocaleFallback=U,window.lnCore.fillTemplate=x,window.lnCore.fill=_,window.lnCore.lnFill=R,window.lnCore.renderList=j);const G="ln:";let b=null;function O(){if(b!==null)return b;try{if(typeof localStorage>"u")return b=!1,!1;const t="__ln_test__";localStorage.setItem(t,t),localStorage.removeItem(t),b=!0}catch{b=!1}return b}function J(){return location.pathname.replace(/\/+$/,"").toLowerCase()||"/"}function K(t,e){const o=e.getAttribute("data-ln-persist"),a=o!==null&&o!==""?o:e.id;return a?G+t+":"+J()+":"+a:(console.warn('[ln-persist] Element requires id or data-ln-persist="key"',e),null)}function X(t,e){if(!O())return null;const o=K(t,e);if(!o)return null;try{const a=localStorage.getItem(o);return a!==null?JSON.parse(a):null}catch{return null}}function $(t,e,o){if(!O())return;const a=K(t,e);if(a)try{o==null?localStorage.removeItem(a):localStorage.setItem(a,JSON.stringify(o))}catch{}}function N(t){return(t||"").replace(/^#/,"")}function y(t){const e=t===void 0?location.hash:t,o={},a=N(e);if(!a)return o;const u=a.split("&");for(let i=0;i<u.length;i++){const r=u[i];if(!r)continue;const s=r.indexOf(":"),n=s>-1?r.slice(0,s):r,l=s>-1?r.slice(s+1):"";if(n)try{o[n]=decodeURIComponent(l)}catch{o[n]=l}}return o}function A(t){if(!t)return null;const e=y();return t in e?e[t]:null}function D(t,e){if(!t)return;const o=y();e==null?delete o[t]:o[t]=String(e);const u=Object.keys(o).map(function(i){const r=o[i];return r===""?i:i+":"+encodeURIComponent(r)}).join("&");N(location.hash)!==u&&(location.hash=u)}function F(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=y,window.lnCore.hashGet=A,window.lnCore.hashSet=D,window.lnCore.hashLinkClick=F),(function(){const t="data-ln-tabs",e="lnTabs";if(window[e]!==void 0&&window[e]!==null)return;function o(i,r){const s=(i.getAttribute("data-ln-tab")||"").toLowerCase().trim();if(s)return s;if(i.tagName!=="A")return"";const n=i.getAttribute("href")||"";if(!n.startsWith("#"))return"";const l=n.slice(1);if(!l)return"";const c=l.split("&");if(r)for(const h of c){const m=h.indexOf(":");if(m>0&&h.slice(0,m).toLowerCase().trim()===r)return h.slice(m+1).toLowerCase().trim()}const f=c[c.length-1]||"",d=f.indexOf(":");return(d>0?f.slice(d+1):f).toLowerCase().trim()}function a(i){return this.dom=i,u.call(this),this}function u(){this.tabs=Array.from(this.dom.querySelectorAll("[data-ln-tab]")),this.panels=Array.from(this.dom.querySelectorAll("[data-ln-panel]"));const i=this.tabs.filter(n=>n.tagName==="A"&&(n.getAttribute("href")||"").startsWith("#")),r=i.length>0&&i.length===this.tabs.length;this.nsKey=(this.dom.getAttribute("data-ln-tabs-key")||this.dom.id||"").toLowerCase().trim(),this.hashEnabled=r&&!!this.nsKey,i.length>0&&i.length!==this.tabs.length?console.warn('[ln-tabs] Mixed <a href="#…"> and <button> triggers in one group — using persist mode. Pick one: anchors for URL hash, buttons for localStorage persist.',this.dom):r&&!this.nsKey&&console.warn("[ln-tabs] Anchor triggers need a hash namespace — add id or data-ln-tabs-key to the wrapper. Falling back to non-hash mode.",this.dom),this.mapTabs={},this.mapPanels={};for(const n of this.tabs){const l=o(n,this.nsKey);l?this.mapTabs[l]=n:console.warn('[ln-tabs] Trigger has no resolvable key — needs `data-ln-tab="key"` or `<a href="#…">`.',n)}for(const n of this.panels){const l=(n.getAttribute("data-ln-panel")||"").toLowerCase().trim();l&&(this.mapPanels[l]=n)}this.defaultKey=(this.dom.getAttribute("data-ln-tabs-default")||"").toLowerCase().trim()||Object.keys(this.mapTabs)[0]||"",this.autoFocus=(this.dom.getAttribute("data-ln-tabs-focus")||"true").toLowerCase()!=="false";const s=this;this._clickHandlers=[];for(const n of this.tabs){if(n[e+"Trigger"])continue;const l=function(c){const f=n.tagName==="A";if(!f&&(c.ctrlKey||c.metaKey||c.button===1))return;const d=o(n,s.nsKey);d&&(f&&!F(c)||(s.hashEnabled?A(s.nsKey)===d?s.dom.setAttribute("data-ln-tabs-active",d):D(s.nsKey,d):s.dom.setAttribute("data-ln-tabs-active",d)))};n.addEventListener("click",l),n[e+"Trigger"]=l,s._clickHandlers.push({el:n,handler:l})}if(this._onRequestSelect=function(n){const l=n.detail&&(n.detail.key||n.detail.tab);l&&s.dom.setAttribute("data-ln-tabs-active",(l+"").toLowerCase().trim())},this.dom.addEventListener("ln-tabs:request-select",this._onRequestSelect),this.dom.addEventListener("ln-tabs:request-activate",this._onRequestSelect),this._hashHandler=function(){if(!s.hashEnabled)return;const n=A(s.nsKey);s.dom.setAttribute("data-ln-tabs-active",n!==null?n:s.defaultKey)},this.hashEnabled)window.addEventListener("hashchange",this._hashHandler),this._hashHandler();else{let n=this.defaultKey;if(this.dom.hasAttribute("data-ln-persist")&&!this.hashEnabled){const l=X("tabs",this.dom);l!==null&&l in this.mapPanels&&(n=l)}this.dom.setAttribute("data-ln-tabs-active",n)}}a.prototype._applyActive=function(i){var r;(!i||!(i in this.mapPanels))&&(i=this.defaultKey);for(const s in this.mapTabs){const n=this.mapTabs[s];s===i?(n.setAttribute("data-active",""),n.setAttribute("aria-selected","true")):(n.removeAttribute("data-active"),n.setAttribute("aria-selected","false"))}for(const s in this.mapPanels){const n=this.mapPanels[s],l=s===i;n.classList.toggle("hidden",!l),n.setAttribute("aria-hidden",l?"false":"true")}if(this.autoFocus){const s=(r=this.mapPanels[i])==null?void 0:r.querySelector('input,button,select,textarea,[tabindex]:not([tabindex="-1"])');s&&setTimeout(()=>s.focus({preventScroll:!0}),0)}S(this.dom,"ln-tabs:change",{key:i,tab:this.mapTabs[i],panel:this.mapPanels[i]}),this.dom.hasAttribute("data-ln-persist")&&!this.hashEnabled&&$("tabs",this.dom,i)},a.prototype.destroy=function(){if(this.dom[e]){this.dom.removeEventListener("ln-tabs:request-select",this._onRequestSelect),this.dom.removeEventListener("ln-tabs:request-activate",this._onRequestSelect);for(const{el:i,handler:r}of this._clickHandlers)i.removeEventListener("click",r),delete i[e+"Trigger"];this.hashEnabled&&window.removeEventListener("hashchange",this._hashHandler),S(this.dom,"ln-tabs:destroyed",{target:this.dom}),delete this.dom[e]}},W(t,e,a,"ln-tabs",{extraAttributes:["data-ln-tabs-active"],onAttributeChange:function(i){const r=i.getAttribute("data-ln-tabs-active");i[e]._applyActive(r)}})})()})();
@@ -1,6 +1,7 @@
1
1
  /* Live Networks - lnTabs (hash-aware tabs — supports <button> and <a href="#nsKey:key"> triggers) */
2
2
  import { registerComponent, dispatch } from '../../ln-core';
3
3
  import { persistGet, persistSet } from '../../ln-core';
4
+ import { hashGet, hashSet, hashLinkClick } from '../../ln-core';
4
5
 
5
6
  (function () {
6
7
  const DOM_SELECTOR = "data-ln-tabs";
@@ -9,17 +10,6 @@ import { persistGet, persistSet } from '../../ln-core';
9
10
  if (window[DOM_ATTRIBUTE] !== undefined && window[DOM_ATTRIBUTE] !== null) return;
10
11
 
11
12
 
12
- function _parseHash() {
13
- const h = (location.hash || "").replace("#", "");
14
- const map = {};
15
- if (!h) return map;
16
- for (const part of h.split("&")) {
17
- const sep = part.indexOf(":");
18
- if (sep > 0) map[part.slice(0, sep)] = part.slice(sep + 1);
19
- }
20
- return map;
21
- }
22
-
23
13
  function _keyFromTrigger(t, nsKey) {
24
14
  const explicit = (t.getAttribute("data-ln-tab") || "").toLowerCase().trim();
25
15
  if (explicit) return explicit;
@@ -48,11 +38,27 @@ import { persistGet, persistSet } from '../../ln-core';
48
38
  this.tabs = Array.from(this.dom.querySelectorAll("[data-ln-tab]"));
49
39
  this.panels = Array.from(this.dom.querySelectorAll("[data-ln-panel]"));
50
40
 
51
- // nsKey/hashEnabled resolved BEFORE mapTabs build — anchor key
52
- // derivation in _keyFromTrigger needs nsKey to pick the right
53
- // fragment.
41
+ // Mode is declared by the TRIGGER TYPE, not by presence of an id:
42
+ // <a href="#…"> → URL hash sync (shareable, back/forward aware)
43
+ // <button> → localStorage persist (opt-in via data-ln-persist)
44
+ // This decouples the two axes that used to collide on `id`: now
45
+ // `id`/`data-ln-tabs-key` only NAMESPACE the hash, and
46
+ // `data-ln-persist` only names the storage key — neither selects the
47
+ // mode. The markup does. Mixed triggers almost always signal a markup
48
+ // mistake, so we fall back to persist and warn rather than guess.
49
+ //
50
+ // nsKey resolved BEFORE mapTabs build — anchor key derivation in
51
+ // _keyFromTrigger needs nsKey to pick the right fragment.
52
+ const anchorTabs = this.tabs.filter(t => t.tagName === "A" && (t.getAttribute("href") || "").startsWith("#"));
53
+ const allAnchors = anchorTabs.length > 0 && anchorTabs.length === this.tabs.length;
54
54
  this.nsKey = (this.dom.getAttribute("data-ln-tabs-key") || this.dom.id || "").toLowerCase().trim();
55
- this.hashEnabled = !!this.nsKey;
55
+ this.hashEnabled = allAnchors && !!this.nsKey;
56
+
57
+ if (anchorTabs.length > 0 && anchorTabs.length !== this.tabs.length) {
58
+ console.warn('[ln-tabs] Mixed <a href="#…"> and <button> triggers in one group — using persist mode. Pick one: anchors for URL hash, buttons for localStorage persist.', this.dom);
59
+ } else if (allAnchors && !this.nsKey) {
60
+ console.warn('[ln-tabs] Anchor triggers need a hash namespace — add id or data-ln-tabs-key to the wrapper. Falling back to non-hash mode.', this.dom);
61
+ }
56
62
 
57
63
  this.mapTabs = {};
58
64
  this.mapPanels = {};
@@ -78,16 +84,18 @@ import { persistGet, persistSet } from '../../ln-core';
78
84
  for (const t of this.tabs) {
79
85
  if (t[DOM_ATTRIBUTE + 'Trigger']) continue;
80
86
  const handler = function (e) {
81
- if (e.ctrlKey || e.metaKey || e.button === 1) return;
87
+ const isAnchor = t.tagName === "A";
88
+ // Buttons keep their plain modifier/middle-click guard. Anchor
89
+ // triggers route through the shared core hash-link helper, which
90
+ // owns the guard (incl. shiftKey) AND the preventDefault — the
91
+ // same path ln-modal uses, so anchor click handling is unified.
92
+ if (!isAnchor && (e.ctrlKey || e.metaKey || e.button === 1)) return;
82
93
  const key = _keyFromTrigger(t, self.nsKey);
83
94
  if (!key) return;
84
- if (t.tagName === "A") e.preventDefault();
95
+ if (isAnchor && !hashLinkClick(e)) return;
85
96
  if (self.hashEnabled) {
86
- const map = _parseHash();
87
- map[self.nsKey] = key;
88
- const newHash = Object.keys(map).map(function (k) { return k + ":" + map[k]; }).join("&");
89
- if (location.hash === "#" + newHash) self.dom.setAttribute('data-ln-tabs-active', key);
90
- else location.hash = newHash;
97
+ if (hashGet(self.nsKey) === key) self.dom.setAttribute('data-ln-tabs-active', key);
98
+ else hashSet(self.nsKey, key);
91
99
  } else {
92
100
  self.dom.setAttribute('data-ln-tabs-active', key);
93
101
  }
@@ -97,10 +105,17 @@ import { persistGet, persistSet } from '../../ln-core';
97
105
  self._clickHandlers.push({ el: t, handler: handler });
98
106
  }
99
107
 
108
+ this._onRequestSelect = function (e) {
109
+ const key = e.detail && (e.detail.key || e.detail.tab);
110
+ if (key) self.dom.setAttribute('data-ln-tabs-active', (key + '').toLowerCase().trim());
111
+ };
112
+ this.dom.addEventListener('ln-tabs:request-select', this._onRequestSelect);
113
+ this.dom.addEventListener('ln-tabs:request-activate', this._onRequestSelect);
114
+
100
115
  this._hashHandler = function () {
101
116
  if (!self.hashEnabled) return;
102
- const map = _parseHash();
103
- self.dom.setAttribute('data-ln-tabs-active', self.nsKey in map ? map[self.nsKey] : self.defaultKey);
117
+ const val = hashGet(self.nsKey);
118
+ self.dom.setAttribute('data-ln-tabs-active', val !== null ? val : self.defaultKey);
104
119
  };
105
120
 
106
121
  if (this.hashEnabled) {
@@ -148,6 +163,8 @@ import { persistGet, persistSet } from '../../ln-core';
148
163
 
149
164
  _component.prototype.destroy = function () {
150
165
  if (!this.dom[DOM_ATTRIBUTE]) return;
166
+ this.dom.removeEventListener('ln-tabs:request-select', this._onRequestSelect);
167
+ this.dom.removeEventListener('ln-tabs:request-activate', this._onRequestSelect);
151
168
  for (const { el, handler } of this._clickHandlers) {
152
169
  el.removeEventListener("click", handler);
153
170
  delete el[DOM_ATTRIBUTE + 'Trigger'];
@@ -79,3 +79,17 @@ Provide a Unix timestamp (in seconds) via `datetime` and specify the formatting
79
79
  - **Passing Millisecond Timestamps:** Standard database fields and JS date objects often return milliseconds (13 digits). `ln-time` maps strictly to Unix seconds (10 digits). Divide milliseconds by `1000` before rendering.
80
80
  - **Using ISO Strings:** `datetime="2025-01-15T14:30:00Z"` is not parsed. The component skips non-numeric values, leaving the original fallback text.
81
81
  - **Empty `datetime` Attributes:** If the `datetime` attribute is omitted or empty, the component will skip formatting to preserve server fallback strings.
82
+
83
+ ---
84
+
85
+ ## 🔧 Internals
86
+
87
+ Source: `js/ln-time/ln-time.js`. Registers via `ln-core`'s `registerComponent` with `extraAttributes: ['datetime']` — the shared observer treats mutations to `datetime` (not just `data-ln-time`) as a re-render trigger, so swapping the timestamp on an existing element re-formats it without a manual re-init call.
88
+
89
+ ### Shared interval
90
+
91
+ All `relative`-mode elements auto-refresh off a single shared `setInterval` (60s), not one timer per element. The interval starts lazily on the first relative element and stops when the last one is gone; elements removed from the DOM without calling `destroy()` are purged from the pool automatically on the next tick rather than leaking.
92
+
93
+ ### Dependencies
94
+
95
+ Built entirely on `Intl.DateTimeFormat` and `Intl.RelativeTimeFormat` (both browser built-ins) — no date-parsing library, no polyfill.
@@ -1 +1 @@
1
- (function(){"use strict";function I(e,n){if(!document.body){document.addEventListener("DOMContentLoaded",function(){I(e,n)}),console.warn("["+n+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function O(e,n,d,v){if(e.nodeType!==1)return;const h=n.indexOf("[")!==-1||n.indexOf(".")!==-1||n.indexOf("#")!==-1?n:"["+n+"]",w=Array.from(e.querySelectorAll(h));e.matches&&e.matches(h)&&w.push(e);for(const i of w)i[d]||(i[d]=new v(i))}function N(e,n,d,v,A={}){const h=A.extraAttributes||[],w=A.onAttributeChange||null,i=A.onInit||null;function c(x){const l=x||document.body;O(l,e,n,d),i&&i(l)}return I(function(){const x=new MutationObserver(function(M){for(let y=0;y<M.length;y++){const r=M[y];if(r.type==="childList"){for(let g=0;g<r.addedNodes.length;g++){const f=r.addedNodes[g];f.nodeType===1&&(O(f,e,n,d),i&&i(f))}for(let g=0;g<r.removedNodes.length;g++){const f=r.removedNodes[g];if(f.nodeType===1){const p=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]",_=Array.from(f.querySelectorAll(p));f.matches&&f.matches(p)&&_.push(f);for(let S=0;S<_.length;S++){const D=_[S];if(!document.contains(D)){const t=D[n];t&&typeof t.destroy=="function"&&t.destroy()}}}}}else r.type==="attributes"&&(w&&r.target[n]?w(r.target,r.attributeName):(O(r.target,e,n,d),i&&i(r.target)))}});let l=[];if(e.indexOf("[")!==-1){const M=/\[([\w-]+)/g;let y;for(;(y=M.exec(e))!==null;)l.push(y[1])}else l.push(e);x.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:l.concat(h)})},v),window[n]=c,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){c(document.body)}):c(document.body),c}const T={};function E(e,n){T[e]=n}function L(e){return T[e]||{ingress:n=>n,egress:n=>n}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=E,window.lnCore.getDataMapper=L),(function(){const e="data-ln-time",n="lnTime";if(window[n]!==void 0)return;const d={},v={};function A(t){return t.getAttribute("data-ln-time-locale")||document.documentElement.lang||void 0}function h(t,o){const s=(t||"")+"|"+JSON.stringify(o);return d[s]||(d[s]=new Intl.DateTimeFormat(t,o)),d[s]}function w(t){const o=t||"";return v[o]||(v[o]=new Intl.RelativeTimeFormat(t,{numeric:"auto",style:"narrow"})),v[o]}const i=new Set;let c=null;function x(){c||(c=setInterval(M,6e4))}function l(){c&&(clearInterval(c),c=null)}function M(){for(const t of i){if(!document.body.contains(t.dom)){i.delete(t);continue}p(t)}i.size===0&&l()}function y(t,o){return h(o,{dateStyle:"long",timeStyle:"short"}).format(t)}function r(t,o){const s=new Date,m={month:"short",day:"numeric"};return t.getFullYear()!==s.getFullYear()&&(m.year="numeric"),h(o,m).format(t)}function g(t,o){return h(o,{dateStyle:"medium"}).format(t)}function f(t,o){return h(o,{timeStyle:"short"}).format(t)}function k(t,o){const s=Math.floor(Date.now()/1e3),b=Math.floor(t.getTime()/1e3)-s,a=Math.abs(b);if(a<10)return w(o).format(0,"second");let u,C;if(a<60)u="second",C=b;else if(a<3600)u="minute",C=Math.round(b/60);else if(a<86400)u="hour",C=Math.round(b/3600);else if(a<604800)u="day",C=Math.round(b/86400);else if(a<2592e3)u="week",C=Math.round(b/604800);else return r(t,o);return w(o).format(C,u)}function p(t){const o=t.dom.getAttribute("datetime");if(!o)return;const s=Number(o);if(isNaN(s))return;const m=new Date(s*1e3),b=t.dom.getAttribute(e)||"short",a=A(t.dom);let u;switch(b){case"relative":u=k(m,a);break;case"full":u=y(m,a);break;case"date":u=g(m,a);break;case"time":u=f(m,a);break;default:u=r(m,a);break}t.dom.textContent=u,b!=="full"&&(t.dom.title=y(m,a))}function _(t){return this.dom=t,p(this),t.getAttribute(e)==="relative"&&(i.add(this),x()),this}_.prototype.render=function(){p(this)},_.prototype.destroy=function(){i.delete(this),i.size===0&&l(),delete this.dom[n]};function S(t){const o=t[n];if(!o)return;t.getAttribute(e)==="relative"?(i.add(o),x()):(i.delete(o),i.size===0&&l()),p(o)}function D(t){t.nodeType===1&&t.hasAttribute&&t.hasAttribute(e)&&t[n]&&p(t[n])}N(e,n,_,"ln-time",{extraAttributes:["datetime"],onAttributeChange:S,onInit:D})})()})();
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 T={};function G(t,e){T[t]||(T[t]=document.querySelector('[data-ln-template="'+t+'"]'));const r=T[t];return r?r.content.cloneNode(!0):(console.warn("["+(e||"ln-core")+'] Template "'+t+'" not found'),null)}function N(t,e){if(!t||!e)return t;const r=t.querySelectorAll("[data-ln-field]");for(let i=0;i<r.length;i++){const o=r[i],l=o.getAttribute("data-ln-field");e[l]!=null&&(o.textContent=e[l])}const u=t.querySelectorAll("[data-ln-attr]");for(let i=0;i<u.length;i++){const o=u[i],l=o.getAttribute("data-ln-attr").split(",");for(let c=0;c<l.length;c++){const f=l[c].trim().split(":");if(f.length!==2)continue;const g=f[0].trim(),m=f[1].trim();e[m]!=null&&o.setAttribute(g,e[m])}}const d=t.querySelectorAll("[data-ln-show]");for(let i=0;i<d.length;i++){const o=d[i],l=o.getAttribute("data-ln-show");l in e&&o.classList.toggle("hidden",!e[l])}const a=t.querySelectorAll("[data-ln-class]");for(let i=0;i<a.length;i++){const o=a[i],l=o.getAttribute("data-ln-class").split(",");for(let c=0;c<l.length;c++){const f=l[c].trim().split(":");if(f.length!==2)continue;const g=f[0].trim(),m=f[1].trim();m in e&&o.classList.toggle(g,!!e[m])}}return t}function P(t,e){t.matches&&t.matches("[data-ln-form], [data-ln-fillable]")&&t.dispatchEvent(new CustomEvent("ln-fill",{detail:e??null,bubbles:!0}));const r=t.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let u=0;u<r.length;u++)r[u].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)N(t.target,t.detail);else{const e=t.target.querySelectorAll("[data-ln-field]");for(let r=0;r<e.length;r++)e[r].textContent=""}})));function R(t,e){if(!t||!e)return t;const r=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(;r.nextNode();){const a=r.currentNode;a.textContent.indexOf("{{")!==-1&&(a.textContent=a.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(i,o){return e[o]!==void 0?e[o]:""}))}const u=function(a,i){return e[i]!==void 0?e[i]:""},d=Array.from(t.querySelectorAll("*"));t.nodeType===1&&d.push(t);for(let a=0;a<d.length;a++){const i=d[a],o=i.attributes;for(let l=0;l<o.length;l++){const c=o[l];c.value.indexOf("{{")!==-1&&i.setAttribute(c.name,c.value.replace(/\{\{\s*(\w+)\s*\}\}/g,u))}}return t}function z(t,e,r,u,d,a){const i={};for(let l=0;l<t.children.length;l++){const c=t.children[l],f=c.getAttribute("data-ln-key");f&&(i[f]=c)}const o=document.createDocumentFragment();for(let l=0;l<e.length;l++){const c=e[l],f=String(u(c));let g=i[f];if(g)d(g,c,l);else{const m=G(r,a);if(!m||(R(m,c),g=m.firstElementChild,!g))continue;g.setAttribute("data-ln-key",f),d(g,c,l)}o.appendChild(g)}t.textContent="",t.appendChild(o)}function j(t,e){if(!document.body){document.addEventListener("DOMContentLoaded",function(){j(t,e)}),console.warn("["+e+'] Script loaded before <body> — add "defer" to your <script> tag');return}t()}function E(t,e,r,u){if(t.nodeType!==1)return;const a=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]",i=Array.from(t.querySelectorAll(a));t.matches&&t.matches(a)&&i.push(t);for(const o of i)o[r]||(o[r]=new u(o))}const $={mk:"mk-MK",de:"de-DE",fr:"fr-FR",es:"es-ES",it:"it-IT",nl:"nl-NL",pt:"pt-PT",ru:"ru-RU",bg:"bg-BG",hr:"hr-HR",sr:"sr-RS",sq:"sq-AL",el:"el-GR",en:"en-US"};function H(t){const e=t?t.closest("[lang]"):null,r=(e?e.getAttribute("lang")||e.lang:null)||(document.documentElement?document.documentElement.getAttribute("lang")||document.documentElement.lang:null)||navigator.language;if(!r)return"en-US";const u=r.trim().toLowerCase();return u.indexOf("-")===-1&&$[u]?$[u]:r}function J(t,e,r,u,d={}){const a=d.extraAttributes||[],i=d.onAttributeChange||null,o=d.onInit||null;function l(c){const f=c||document.body;E(f,t,e,r),o&&o(f)}return j(function(){const c=new MutationObserver(function(g){for(let m=0;m<g.length;m++){const y=g[m];if(y.type==="childList"){for(let v=0;v<y.addedNodes.length;v++){const A=y.addedNodes[v];A.nodeType===1&&(E(A,t,e,r),o&&o(A))}for(let v=0;v<y.removedNodes.length;v++){const A=y.removedNodes[v];if(A.nodeType===1){const L=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",x=Array.from(A.querySelectorAll(L));A.matches&&A.matches(L)&&x.push(A);for(let _=0;_<x.length;_++){const O=x[_];if(!document.contains(O)){const k=O[e];k&&typeof k.destroy=="function"&&k.destroy()}}}}}else y.type==="attributes"&&(i&&y.target[e]?i(y.target,y.attributeName):(E(y.target,t,e,r),o&&o(y.target)))}});let f=[];if(t.indexOf("[")!==-1){const g=/\[([\w-]+)/g;let m;for(;(m=g.exec(t))!==null;)f.push(m[1])}else f.push(t);c.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:f.concat(a)})},u),window[e]=l,document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){l(document.body)}):l(document.body),l}const W={};function X(t,e){W[t]=e}function Q(t){return W[t]||{ingress:e=>e,egress:e=>e}}const B={};function U(t,e){if(!t||typeof e!="object")return;const r=t.toLowerCase().split("-")[0];B[r]=e}function M(t){if(!t)return null;const e=t.toLowerCase().split("-")[0];return B[e]||null}U("mk",{monthsLong:["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември"],monthsShort:["јан","фев","мар","апр","мај","јун","јул","авг","септ","окт","ноем","дек"],daysLong:["недела","понеделник","вторник","среда","четврток","петок","сабота"],daysShort:["нед","пон","вт","ср","чет","пет","саб"]}),typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=X,window.lnCore.getDataMapper=Q,window.lnCore.registerLocaleFallback=U,window.lnCore.getLocaleFallback=M,window.lnCore.fillTemplate=R,window.lnCore.fill=N,window.lnCore.lnFill=P,window.lnCore.renderList=z);function Y(t){return(t||"").replace(/^#/,"")}function D(t){const e=t===void 0?location.hash:t,r={},u=Y(e);if(!u)return r;const d=u.split("&");for(let a=0;a<d.length;a++){const i=d[a];if(!i)continue;const o=i.indexOf(":"),l=o>-1?i.slice(0,o):i,c=o>-1?i.slice(o+1):"";if(l)try{r[l]=decodeURIComponent(c)}catch{r[l]=c}}return r}function V(t){if(!t)return null;const e=D();return t in e?e[t]:null}function Z(t,e){if(!t)return;const r=D();e==null?delete r[t]:r[t]=String(e);const d=Object.keys(r).map(function(a){const i=r[a];return i===""?a:a+":"+encodeURIComponent(i)}).join("&");Y(location.hash)!==d&&(location.hash=d)}function tt(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=D,window.lnCore.hashGet=V,window.lnCore.hashSet=Z,window.lnCore.hashLinkClick=tt),(function(){const t="data-ln-time",e="lnTime";if(window[e]!==void 0)return;const r={},u={};function d(n){return n.getAttribute("data-ln-time-locale")||H(n)}function a(n,s){const h=(n||"")+"|"+JSON.stringify(s);return r[h]||(r[h]=new Intl.DateTimeFormat(n,s)),r[h]}function i(n){const s=n||"";return u[s]||(u[s]=new Intl.RelativeTimeFormat(n,{numeric:"auto",style:"narrow"})),u[s]}const o=new Set;let l=null;function c(){l||(l=setInterval(g,6e4))}function f(){l&&(clearInterval(l),l=null)}function g(){for(const n of o){if(!document.body.contains(n.dom)){o.delete(n);continue}L(n)}o.size===0&&f()}function m(n,s){const h=M(s),C=(s||"").toLowerCase().split("-")[0],b=a(s,{dateStyle:"long",timeStyle:"short"}),w=b.resolvedOptions().locale.toLowerCase().split("-")[0];if(h&&w!==C&&h.monthsLong){const p=h.monthsLong[n.getMonth()],S=n.getDate(),F=n.getFullYear(),q=String(n.getHours()).padStart(2,"0"),I=String(n.getMinutes()).padStart(2,"0");return`${S} ${p} ${F} во ${q}:${I}`}return b.format(n)}function y(n,s){const h=new Date,C={month:"short",day:"numeric"};n.getFullYear()!==h.getFullYear()&&(C.year="numeric");const b=M(s),w=(s||"").toLowerCase().split("-")[0],p=a(s,C),S=p.resolvedOptions().locale.toLowerCase().split("-")[0];if(b&&S!==w&&b.monthsShort){const F=b.monthsShort[n.getMonth()],q=n.getDate(),I=n.getFullYear()!==h.getFullYear()?" "+n.getFullYear():"";return`${q} ${F}${I}`}return p.format(n)}function v(n,s){return a(s,{dateStyle:"medium"}).format(n)}function A(n,s){return a(s,{timeStyle:"short"}).format(n)}function K(n,s){const h=Math.floor(Date.now()/1e3),b=Math.floor(n.getTime()/1e3)-h,w=Math.abs(b);if(w<10)return i(s).format(0,"second");let p,S;if(w<60)p="second",S=b;else if(w<3600)p="minute",S=Math.round(b/60);else if(w<86400)p="hour",S=Math.round(b/3600);else if(w<604800)p="day",S=Math.round(b/86400);else if(w<2592e3)p="week",S=Math.round(b/604800);else return y(n,s);return i(s).format(S,p)}function L(n){const s=n.dom.getAttribute("datetime");if(!s)return;const h=Number(s);if(isNaN(h))return;const C=new Date(h*1e3),b=n.dom.getAttribute(t)||"short",w=d(n.dom);let p;switch(b){case"relative":p=K(C,w);break;case"full":p=m(C,w);break;case"date":p=v(C,w);break;case"time":p=A(C,w);break;default:p=y(C,w);break}n.dom.textContent=p,b!=="full"&&(n.dom.title=m(C,w))}function x(n){return this.dom=n,L(this),n.getAttribute(t)==="relative"&&(o.add(this),c()),this}x.prototype.render=function(){L(this)},x.prototype.destroy=function(){o.delete(this),o.size===0&&f(),delete this.dom[e]};function _(n){const s=n[e];if(!s)return;n.getAttribute(t)==="relative"?(o.add(s),c()):(o.delete(s),o.size===0&&f()),L(s)}function O(n){n.nodeType===1&&n.hasAttribute&&n.hasAttribute(t)&&n[e]&&L(n[e])}function k(){new MutationObserver(function(){const n=document.querySelectorAll("["+t+"]");for(let s=0;s<n.length;s++){const h=n[s][e];h&&L(h)}}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})}J(t,e,x,"ln-time",{extraAttributes:["datetime","data-ln-time-locale","lang"],onAttributeChange:_,onInit:O}),k()})()})();