@livenetworks/ashlar 2.0.2 → 2.0.4

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.
@@ -1,7 +1,25 @@
1
1
  import {
2
2
  registerComponent, dispatch, dispatchCancelable, guardBody, findElements, shouldInterceptLink
3
3
  } from '../../ln-core';
4
- import { planRegions } from './router-model.js';
4
+ import { planRegions, normalizeBase, stripBase, toAbsoluteUrl } from './router-model.js';
5
+
6
+ function _getBase() {
7
+ if (typeof document === 'undefined') return '';
8
+ const outlet = document.querySelector('[data-ln-outlet]') || document.querySelector('[data-ln-router-base]');
9
+ if (outlet && outlet.hasAttribute('data-ln-router-base')) {
10
+ return normalizeBase(outlet.getAttribute('data-ln-router-base'));
11
+ }
12
+ const baseEl = document.querySelector('base[href]');
13
+ if (baseEl) {
14
+ try {
15
+ const u = new URL(baseEl.getAttribute('href'), window.location.origin);
16
+ return normalizeBase(u.pathname);
17
+ } catch (e) {
18
+ return normalizeBase(baseEl.getAttribute('href'));
19
+ }
20
+ }
21
+ return '';
22
+ }
5
23
 
6
24
  // Singleton router implementation
7
25
  export const router = {
@@ -11,10 +29,18 @@ export const router = {
11
29
  replace: function (fullPath) {
12
30
  _navigate(fullPath, { historyAction: 'replace' });
13
31
  },
32
+ base: function () {
33
+ return _getBase();
34
+ },
35
+ toUrl: function (relPath) {
36
+ return toAbsoluteUrl(relPath, _getBase());
37
+ },
14
38
  current: function () {
15
39
  if (currentPath === null) return null;
16
40
  return {
17
41
  path: currentPath,
42
+ fullPath: currentFullPath,
43
+ base: currentBase,
18
44
  params: currentParams,
19
45
  query: currentQuery,
20
46
  route: currentRoute,
@@ -42,6 +68,7 @@ const ATTRIBUTES = {
42
68
  'data-ln-route-target': { effect: _reRegisterRoute, type: 'string', description: 'Target outlet element selector where route content is rendered' },
43
69
  'data-ln-route-title': { effect: _reRegisterRoute, type: 'string', description: 'Document title template set when route is activated' },
44
70
  'data-ln-route-keep': { type: 'boolean', fallback: false, description: 'Preserve mounted DOM nodes in memory instead of rebuilding' },
71
+ 'data-ln-router-base': { type: 'string', description: 'Base URL prefix for subdirectory routing (e.g. "/spa")' },
45
72
  'data-ln-router-hydrate': { type: 'boolean', fallback: false, description: 'Hydrate existing DOM content on initial router boot' }
46
73
  };
47
74
 
@@ -57,6 +84,8 @@ let currentRegions = new Map();
57
84
 
58
85
  let booted = false;
59
86
  let currentPath = null;
87
+ let currentFullPath = null;
88
+ let currentBase = '';
60
89
  let currentParams = {};
61
90
  let currentQuery = {};
62
91
  let currentRoute = null;
@@ -77,7 +106,7 @@ function _dispatchMaybeDeferred(target, name, detail) {
77
106
  }
78
107
 
79
108
  /**
80
- * Normalize path: collapse trailing slash, strip query/hash, parse query.
109
+ * Normalize path: collapse trailing slash, strip query/hash, parse query, strip base.
81
110
  */
82
111
  function _normalizePath(fullPath) {
83
112
  // Absolute same-origin URLs (route() helpers, anchor.href) → reduce to
@@ -90,7 +119,7 @@ function _normalizePath(fullPath) {
90
119
  } catch (e) { /* not a parseable URL — use fullPath as-is */ }
91
120
 
92
121
  let [pathAndQuery] = fullPath.split('#');
93
- let [path, queryString] = pathAndQuery.split('?');
122
+ let [rawPath, queryString] = pathAndQuery.split('?');
94
123
 
95
124
  const query = {};
96
125
  if (queryString) {
@@ -100,12 +129,10 @@ function _normalizePath(fullPath) {
100
129
  }
101
130
  }
102
131
 
103
- path = path.replace(/\/+$/, '');
104
- if (path === '') {
105
- path = '/';
106
- }
132
+ const base = _getBase();
133
+ const path = stripBase(rawPath, base);
107
134
 
108
- return { path, query };
135
+ return { path, query, base };
109
136
  }
110
137
 
111
138
  /**
@@ -261,7 +288,8 @@ function _teardownOutlet(target) {
261
288
  * swaps all regions that need it inside a single view transition.
262
289
  */
263
290
  function _navigate(fullPath, opts = {}) {
264
- const { path, query } = _normalizePath(fullPath);
291
+ const { path, query, base } = _normalizePath(fullPath);
292
+ const historyPath = toAbsoluteUrl(fullPath, base);
265
293
 
266
294
  // 1. Per-region match
267
295
  const regionMatches = new Map();
@@ -329,7 +357,8 @@ function _navigate(fullPath, opts = {}) {
329
357
  // one match, regardless of whether the primary is among them.
330
358
  const beforeEvent = dispatchCancelable(primaryTarget || document.body, 'ln-router:before-navigate', {
331
359
  from: currentPath,
332
- to: fullPath,
360
+ to: historyPath,
361
+ path: path,
333
362
  params: primaryMatch ? primaryMatch.params : {},
334
363
  query
335
364
  });
@@ -337,9 +366,9 @@ function _navigate(fullPath, opts = {}) {
337
366
 
338
367
  // 7. History update (once per navigation)
339
368
  if (opts.historyAction === 'push') {
340
- window.history.pushState(null, '', fullPath);
369
+ window.history.pushState(null, '', historyPath);
341
370
  } else if (opts.historyAction === 'replace') {
342
- window.history.replaceState(null, '', fullPath);
371
+ window.history.replaceState(null, '', historyPath);
343
372
  }
344
373
 
345
374
  // 8. Atomic swap — one view transition wraps every region clear/mount.
@@ -395,7 +424,9 @@ function _navigate(fullPath, opts = {}) {
395
424
  }
396
425
 
397
426
  _dispatchMaybeDeferred(d.targetEl, 'ln-router:navigated', {
398
- path: fullPath,
427
+ path: path,
428
+ fullPath: historyPath,
429
+ base: base,
399
430
  params: d.match.params,
400
431
  query,
401
432
  route: d.match.route,
@@ -406,10 +437,12 @@ function _navigate(fullPath, opts = {}) {
406
437
 
407
438
  // State is read off the primary match — currentRoute is null on an
408
439
  // aux-only navigation, which is what current() === null now hinges on.
409
- currentPath = fullPath;
410
- currentQuery = query;
411
- currentRoute = primaryMatch ? primaryMatch.route : null;
412
- currentParams = primaryMatch ? primaryMatch.params : {};
440
+ currentPath = path;
441
+ currentFullPath = historyPath;
442
+ currentBase = base;
443
+ currentQuery = query;
444
+ currentRoute = primaryMatch ? primaryMatch.route : null;
445
+ currentParams = primaryMatch ? primaryMatch.params : {};
413
446
 
414
447
  // currentRegions reflects every region's match (null when unmatched).
415
448
  // Built from regionMatches — never from the loop variable `match`.
@@ -455,20 +488,10 @@ function _queryEqual(a, b) {
455
488
 
456
489
  function _onPopState() {
457
490
  const fullPath = window.location.pathname + window.location.search;
458
- // Fragment-only popstate guard: when Back/Forward changes ONLY the hash
459
- // (path + query identical to the current SPA state), skip navigation so the
460
- // primary outlet is not torn down and re-cloned. Hash-bound components
461
- // (e.g. ln-modal) react to the accompanying hashchange independently.
462
- //
463
- // cur.query is the authoritative already-parsed query for the active route
464
- // (currentQuery), so compare target.query against it directly. cur.path is
465
- // the raw fullPath (retains the query string), so normalize it for the
466
- // pathname comparison only — do NOT re-parse it for the query.
467
491
  const cur = router.current();
468
492
  if (cur && cur.path != null) {
469
493
  const target = _normalizePath(fullPath);
470
- const currentPathNorm = _normalizePath(cur.path).path;
471
- if (currentPathNorm === target.path && _queryEqual(cur.query, target.query)) {
494
+ if (cur.path === target.path && _queryEqual(cur.query, target.query)) {
472
495
  return;
473
496
  }
474
497
  }
@@ -48,3 +48,88 @@ export function planRegions(descriptors, { isHydration = false, hasPrimaryRegion
48
48
 
49
49
  return { notFound, clears, swaps, owner };
50
50
  }
51
+
52
+ /**
53
+ * Normalizes a base URL string:
54
+ * - ensures leading slash
55
+ * - strips trailing slash
56
+ * - returns empty string if root '/' or empty
57
+ * e.g. '/spa/' -> '/spa', 'spa' -> '/spa', '/' -> '', '' -> ''
58
+ *
59
+ * @param {string|null|undefined} base
60
+ * @returns {string}
61
+ */
62
+ export function normalizeBase(base) {
63
+ if (!base || typeof base !== 'string') return '';
64
+ let b = base.trim().replace(/\/+$/, '');
65
+ if (!b || b === '/') return '';
66
+ return b.startsWith('/') ? b : '/' + b;
67
+ }
68
+
69
+ /**
70
+ * Strips the base URL prefix from a pathname, returning the clean relative path.
71
+ * e.g. with base '/spa':
72
+ * '/spa/packages' -> '/packages'
73
+ * '/spa' -> '/'
74
+ * '/spa/' -> '/'
75
+ * '/packages' -> '/packages' (already relative)
76
+ * '/' -> '/'
77
+ *
78
+ * @param {string} path
79
+ * @param {string} [base]
80
+ * @returns {string}
81
+ */
82
+ export function stripBase(path, base) {
83
+ const b = normalizeBase(base);
84
+ if (!b) return (path && path.replace(/\/+$/, '')) || '/';
85
+
86
+ const normalizedPath = (path || '/').replace(/\/+$/, '') || '/';
87
+
88
+ if (normalizedPath === b) {
89
+ return '/';
90
+ }
91
+ if (normalizedPath.startsWith(b + '/')) {
92
+ const rel = normalizedPath.slice(b.length);
93
+ return rel.replace(/\/+$/, '') || '/';
94
+ }
95
+ return normalizedPath;
96
+ }
97
+
98
+ /**
99
+ * Converts a relative path into an absolute path prefixed with base.
100
+ * Preserves query strings and hashes.
101
+ * e.g. with base '/spa':
102
+ * '/packages' -> '/spa/packages'
103
+ * '/' -> '/spa/'
104
+ * 'packages' -> '/spa/packages'
105
+ * '/spa/packages' -> '/spa/packages' (already prefixed)
106
+ *
107
+ * @param {string} relPath
108
+ * @param {string} [base]
109
+ * @returns {string}
110
+ */
111
+ export function toAbsoluteUrl(relPath, base) {
112
+ const b = normalizeBase(base);
113
+ if (!b) return relPath || '/';
114
+
115
+ const str = relPath || '/';
116
+ const hashIdx = str.indexOf('#');
117
+ const pathAndQuery = hashIdx !== -1 ? str.slice(0, hashIdx) : str;
118
+ const hash = hashIdx !== -1 ? str.slice(hashIdx) : '';
119
+
120
+ const queryIdx = pathAndQuery.indexOf('?');
121
+ const pathname = queryIdx !== -1 ? pathAndQuery.slice(0, queryIdx) : pathAndQuery;
122
+ const queryString = queryIdx !== -1 ? pathAndQuery.slice(queryIdx) : '';
123
+
124
+ let absPath;
125
+ if (pathname === b) {
126
+ absPath = b + '/';
127
+ } else if (pathname.startsWith(b + '/')) {
128
+ absPath = pathname;
129
+ } else {
130
+ const cleanRel = pathname.startsWith('/') ? pathname : '/' + pathname;
131
+ absPath = cleanRel === '/' ? b + '/' : b + cleanRel;
132
+ }
133
+
134
+ return absPath + queryString + hash;
135
+ }
@@ -1 +1 @@
1
- (function(){"use strict";function $(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function _(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){o=t[r];break}if(!_(o))return}e.apply(console,t)}}function U(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function A(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){A(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const N={};function Q(e,t){N[e]=t}function J(e){return N[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=Q,window.lnCore.getDataMapper=J);function K(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){U(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const M={};function G(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];M[n]=t}function z(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return M[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=G,window.lnCore.getLocaleFallback=z,window.lnCore.ensureLocaleObserver=K);const v={};function B(e,t){v[e]||(v[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=v[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function X(e,t,n){if(e){const o=e.querySelector('[data-ln-template="'+t+'"]');if(o)return o.content.cloneNode(!0)}return B(t,n)}function S(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++){const a=n[l],c=a.getAttribute("data-ln-field");t[c]!=null&&(a.textContent=t[c])}const o=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<o.length;l++){const a=o[l],c=a.getAttribute("data-ln-attr").split(",");for(let f=0;f<c.length;f++){const h=c[f].trim().split(":");if(h.length!==2)continue;const w=h[0].trim(),m=h[1].trim();t[m]!=null&&a.setAttribute(w,t[m])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const a=r[l],c=a.getAttribute("data-ln-show");c in t&&a.classList.toggle("hidden",!t[c])}const i=e.querySelectorAll("[data-ln-class]");for(let l=0;l<i.length;l++){const a=i[l],c=a.getAttribute("data-ln-class").split(",");for(let f=0;f<c.length;f++){const h=c[f].trim().split(":");if(h.length!==2)continue;const w=h[0].trim(),m=h[1].trim();m in t&&a.classList.toggle(w,!!t[m])}}return e}function Y(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)S(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function F(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const i=n.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,a){return t[a]!==void 0?t[a]:""}))}const o=function(i,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let i=0;i<r.length;i++){const l=r[i],a=l.attributes;for(let c=0;c<a.length;c++){const f=a[c];f.value.indexOf("{{")!==-1&&l.setAttribute(f.name,f.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function Z(e,t,n,o,r,i){const l={};for(let c=0;c<e.children.length;c++){const f=e.children[c],h=f.getAttribute("data-ln-render-key");h&&(l[h]=f)}const a=document.createDocumentFragment();for(let c=0;c<t.length;c++){const f=t[c],h=String(o(f));let w=l[h];if(w)r(w,f,c);else{const m=B(n,i);if(!m||(F(m,f),w=m.firstElementChild,!w))continue;w.setAttribute("data-ln-render-key",h),r(w,f,c)}a.appendChild(w)}e.textContent="",e.appendChild(a)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=F,window.lnCore.fill=S,window.lnCore.lnFill=Y,window.lnCore.renderList=Z);function R(e,t,n){const o=e.getAttribute(t);return o===null?n:o}function k(e,t,n){const o=parseInt(e.getAttribute(t),10);return isNaN(o)?n:o}function ee(e,t,n=!1){const o=e.getAttribute(t);if(o===null)return!!n;const r=o.trim().toLowerCase();return!(r==="false"||r==="0")}function te(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const E=new Map;function ne(e,t){const n=(e?e.join("|"):"")+"::"+t;if(E.has(n))return E.get(n);const o=new Set(e||[]),r=function(i,l){const a=i.getAttribute(l);return a!==null&&o.has(a)?a:t};return E.set(n,r),r}function oe(e,t,n){const o=parseFloat(e.getAttribute(t));return isNaN(o)?n:o}function re(e,t,n){const o=e.getAttribute(t);if(!o)return n;try{return JSON.parse(o)}catch{return n}}function j(e,t,n,o,r){if(!e||t===null)return!0;const i=o||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const a=c=>{r?console.warn(c,r):console.warn(c)};if(l==="boolean"){const c=t.trim().toLowerCase();return c!==""&&c!=="true"&&c!=="false"&&c!=="1"&&c!=="0"?(a(`[${i}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const c=e.values||[];return c.includes(t)?!0:(a(`[${i}] Invalid value "${t}" for attribute "${n}". Allowed: ${c.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return a(`[${i}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const c=parseInt(t,10);return e.min!==void 0&&c<e.min?(a(`[${i}] Value ${c} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&c>e.max?(a(`[${i}] Value ${c} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(a(`[${i}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(c){return a(`[${i}] Invalid JSON for attribute "${n}": ${c.message}. Fallback: ${e.fallback}.`),!1}return!0}function ie(e,t,n){for(const o in n){const[r,i,l]=n[o];Object.defineProperty(e,o,{get:function(){return r(t,i,l)},enumerable:!0,configurable:!0})}return e}function le(e){const t={};for(const n in e){const o=e[n];if(!o||!o.prop)continue;let r=o.read;if(!r&&o.type)switch(o.type){case"enum":r=ne(o.values,o.fallback);break;case"integer":r=k;break;case"float":r=oe;break;case"boolean":r=ee;break;case"list":r=te;break;case"json":r=re;break;case"string":default:r=R;break}r||(r=R),t[o.prop]=[r,n,o.fallback]}return t}function se(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function ae(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function L(e,t,n,o){if(e.nodeType!==1)return;const i=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l=Array.from(e.querySelectorAll(i));e.matches&&e.matches(i)&&l.push(e);for(const a of l)if(!a[n]){window.lnCore._persistSink&&a.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(a,t);try{a[n]=new o(a)}catch(c){console.error("["+n+"] init failed",a,c)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function ce(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function ue(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function W(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function de(e){const t=W(),n=e.observed||[];for(let o=0;o<n.length;o++){const r=n[o];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const r=t.byDeclaredAttr.get(o);r.some(i=>i.componentTag===e.componentTag)||r.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=ae(e);if(o===null)t.reactiveWildcard.push(e);else for(const r of o)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function H(e,t,n,o){for(let r=0;r<e.length;r++){const i=e[r];if(!t[i.attribute])continue;const l=i.effects&&i.effects[n];l?l(t,n,o):i.onAttrChange&&(!i.declared||i.declared.has(n))&&i.onAttrChange(t,n,o)}}function fe(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=W(),r=o.byAttr.get(n);if($()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&_(t)){const i=o.byDeclaredAttr.get(n),l=t.getAttribute(n);for(let a=0;a<i.length;a++)j(i[a].spec,l,n,i[a].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||r)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const i=o.byReactive.get(n);i&&H(i,t,n,e.oldValue),o.reactiveWildcard.length&&H(o.reactiveWildcard,t,n,e.oldValue)}if(r)for(let i=0;i<r.length;i++){const l=r[i];if(l.handler){l.handler(t,n,e.oldValue);continue}l.onAttributeChange&&t[l.attribute]?l.onAttributeChange(t,n):(L(t,l.selector,l.attribute,l.ComponentFn),l.onInit&&l.onInit(t))}}function we(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{fe(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function V(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function he(e){const t=V();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const r=o.query,i=e.target.nodeType===1?e.target.matches(r)?e.target:e.target.closest(r):e.target.parentElement?e.target.parentElement.closest(r):null;i&&o.onSubtreeChange(i,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r];L(o,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r],l=i.query,a=Array.from(o.querySelectorAll(l));o.matches&&o.matches(l)&&a.push(o);for(let c=0;c<a.length;c++){const f=a[c];if(!document.contains(f)){const h=f[i.attribute];if(h&&typeof h.destroy=="function")try{h.destroy()}catch(w){console.error("["+i.attribute+"] destroy failed",f,w)}delete f[i.attribute]}}}}}}function pe(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{he(o)}catch(r){console.error("[ln-core] lifecycle handler failed",o.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function be(e,t,n,o,r={}){const i=r.extraAttributes||[],l=r.onAttributeChange||null,a=r.onSubtreeChange||null,c=r.onInit||null,f=r.onAttrChange||null,h=r.effects||null,w=r.attributes||null,m=w?se(w):h,O=w?new Set(Object.keys(w)):null,x=r.persist||null;function C(b){const g=b||document.body;if(L(g,e,t,n),w&&$())for(const y in w){const ke=w[y],q=Array.from(g.querySelectorAll("["+y+"]"));g.matches&&g.matches("["+y+"]")&&q.push(g);for(let I=0;I<q.length;I++){const D=q[I];_(D)&&j(ke,D.getAttribute(y),y,o,D)}}c&&c(g)}const s=[];if(e.indexOf("[")!==-1){const b=/\[([\w-]+)/g;let g;for(;(g=b.exec(e))!==null;)s.push(g[1])}else s.push(e);de({selector:e,attribute:t,componentTag:o,attributes:w,ComponentFn:n,onInit:c,observed:s.concat(i),onAttributeChange:l,onAttrChange:f,effects:m,declared:O,persist:x}),we();const d=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";V().push({selector:e,attribute:t,ComponentFn:n,onInit:c,onSubtreeChange:a,query:d}),pe(),window[t]=C;function p(){ce()>0?ue(function(){C(document.body)}):C(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p(),C}function P(e){return(e||"").replace(/^#/,"")}function T(e){const t=e===void 0?location.hash:e,n={},o=P(t);if(!o)return n;const r=o.split("&");for(let i=0;i<r.length;i++){const l=r[i];if(!l)continue;const a=l.indexOf(":"),c=a>-1?l.slice(0,a):l,f=a>-1?l.slice(a+1):"";if(c)try{n[c]=decodeURIComponent(f)}catch{n[c]=f}}return n}function me(e){if(!e)return null;const t=T();return e in t?t[e]:null}function ge(e,t){if(!e)return;const n=T();t==null?delete n[e]:n[e]=String(t);const r=Object.keys(n).map(function(i){const l=n[i];return l===""?i:i+":"+encodeURIComponent(l)}).join("&");P(location.hash)!==r&&(location.hash=r)}function ye(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Ce(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function Ae(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function _e(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ve(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Se(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),r=o?o.split(",").map(function(i){try{return decodeURIComponent(i)}catch{return i}}).filter(Boolean):[];return{key:n,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=T,window.lnCore.hashGet=me,window.lnCore.hashSet=ge,window.lnCore.hashLinkClick=ye,window.lnCore.resolveHashNamespace=Ce,window.lnCore.hashSortEncode=Ae,window.lnCore.hashSortDecode=_e,window.lnCore.hashFilterEncode=ve,window.lnCore.hashFilterDecode=Se),(function(){const e="data-ln-toast",t="lnToast",n="ln-toast-item";if(window[t]!==void 0)return;const o={"data-ln-toast":{type:"marker",description:"Initializes the toast notifications container"},"data-ln-toast-timeout":{prop:"timeoutDefault",type:"integer",read:k,fallback:6e3,min:500,description:"Default auto-dismiss timeout in ms"},"data-ln-toast-max":{prop:"max",type:"integer",read:k,fallback:5,min:1,description:"Maximum visible concurrent toast notifications"},"data-ln-toast-close":{type:"trigger",description:"Click dismiss trigger inside a toast item"},"data-ln-toast-item":{type:"marker",description:"Individual toast notification element"}},r=le(o);function i(s){if(!(!s||!(s instanceof HTMLElement))&&(s.hasAttribute("popover")||s.setAttribute("popover","manual"),typeof s.showPopover=="function")){if(s.matches(":popover-open"))try{s.hidePopover()}catch{}try{s.showPopover()}catch{}}}function l(s){if(!s||!(s instanceof HTMLElement))return;if(s.querySelectorAll("[data-ln-toast-item]").length===0&&typeof s.hidePopover=="function"&&s.matches(":popover-open"))try{s.hidePopover()}catch{}}function a(s){this.dom=s,ie(this,s,r);const u=Array.from(s.querySelectorAll("[data-ln-toast-item]"));for(;u.length>this.max;)s.removeChild(u.shift());for(const d of u)O(d,this);return u.length>0&&i(s),this}a.prototype.enqueue=function(s){if(!s)return;const u=c(s,this.dom);if(!u)return;const d=Number.isFinite(s.timeout)?s.timeout:this.timeoutDefault;h(this,u),d>0&&(u._timer=setTimeout(()=>w(u),d))},a.prototype.clear=function(){for(const s of Array.from(this.dom.querySelectorAll("[data-ln-toast-item]")))w(s)},a.prototype.destroy=function(){if(this.dom[t]){for(const s of Array.from(this.dom.querySelectorAll("[data-ln-toast-item]")))w(s);l(this.dom),delete this.dom[t]}};function c(s,u){const d=((s.type||"")+"").trim().toLowerCase(),p=X(u,n,"ln-toast");if(!p)return console.warn('[ln-toast] Template "'+n+'" not found'),null;S(p,{type:d,title:s.title,message:typeof s.message=="string"?s.message:void 0});const b=p.firstElementChild;if(!b)return null;b.hasAttribute("data-ln-toast-item")||b.setAttribute("data-ln-toast-item",""),b.classList.add("ln-enter");const g=b.querySelector(".body");g&&f(g,s);const y=b.querySelector("[data-ln-toast-close]");return y&&y.addEventListener("click",function(){w(b)}),b}function f(s,u){if(Array.isArray(u.message)){const d=document.createElement("ul");for(const p of u.message){const b=document.createElement("li");b.textContent=p,d.appendChild(b)}s.appendChild(d)}if(u.data&&u.data.errors){const d=document.createElement("ul");for(const p of Object.values(u.data.errors).flat()){const b=document.createElement("li");b.textContent=p,d.appendChild(b)}s.appendChild(d)}}function h(s,u){const d=Array.from(s.dom.querySelectorAll("[data-ln-toast-item]"));for(;d.length>=s.max&&d.length>0;)s.dom.removeChild(d.shift());s.dom.appendChild(u),i(s.dom),requestAnimationFrame(()=>u.classList.remove("ln-enter"))}function w(s){if(!s||!s.parentNode)return;const u=s.parentNode;clearTimeout(s._timer),s.classList.remove("ln-enter"),s.classList.add("ln-out"),setTimeout(()=>{s.parentNode&&(s.parentNode.removeChild(s),l(u))},200)}function m(s){let u=s&&s.container;return typeof u=="string"&&(u=document.querySelector(u)),u instanceof HTMLElement||(u=document.querySelector("["+e+"]")||document.getElementById("ln-toast-container")),u||null}function O(s,u){if(s._lnToastHydrated)return;s._lnToastHydrated=!0;const d=s.querySelector("[data-ln-toast-close]");d&&d.addEventListener("click",function(){w(s)});const p=+(s.getAttribute("data-ln-toast-timeout")??u.timeoutDefault);p>0&&(s._timer=setTimeout(function(){w(s)},p))}function x(s){const u=s.detail||{},d=m(u);if(!d){console.warn("[ln-toast] No toast container found");return}(d[t]||(d[t]=new a(d))).enqueue(u)}function C(s){const u=s&&s.detail||{};if(u.container){const d=m(u);d&&(d[t]||(d[t]=new a(d))).clear()}else{const d=document.querySelectorAll("["+e+"]");for(const p of Array.from(d))(p[t]||(p[t]=new a(p))).clear()}}A(function(){window.addEventListener("ln-toast:enqueue",x),window.addEventListener("ln-toast:clear",C),window.addEventListener("ln-modal:open",function(){const s=document.querySelectorAll("["+e+"]");for(const u of Array.from(s))u.querySelectorAll("[data-ln-toast-item]").length>0&&i(u)})},"ln-toast"),be(e,t,a,"ln-toast",{attributes:o})})()})();
1
+ (function(){"use strict";function $(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function _(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){o=t[r];break}if(!_(o))return}e.apply(console,t)}}function U(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function A(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){A(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const N={};function Q(e,t){N[e]=t}function J(e){return N[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=Q,window.lnCore.getDataMapper=J);function K(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){U(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const M={};function G(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];M[n]=t}function z(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return M[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=G,window.lnCore.getLocaleFallback=z,window.lnCore.ensureLocaleObserver=K);const v={};function B(e,t){v[e]||(v[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=v[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function X(e,t,n){if(e){const o=e.querySelector('[data-ln-template="'+t+'"]');if(o)return o.content.cloneNode(!0)}return B(t,n)}function S(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++){const a=n[l],c=a.getAttribute("data-ln-field");t[c]!=null&&(a.textContent=t[c])}const o=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<o.length;l++){const a=o[l],c=a.getAttribute("data-ln-attr").split(",");for(let f=0;f<c.length;f++){const h=c[f].trim().split(":");if(h.length!==2)continue;const w=h[0].trim(),m=h[1].trim();t[m]!=null&&a.setAttribute(w,t[m])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const a=r[l],c=a.getAttribute("data-ln-show");c in t&&a.classList.toggle("hidden",!t[c])}const i=e.querySelectorAll("[data-ln-class]");for(let l=0;l<i.length;l++){const a=i[l],c=a.getAttribute("data-ln-class").split(",");for(let f=0;f<c.length;f++){const h=c[f].trim().split(":");if(h.length!==2)continue;const w=h[0].trim(),m=h[1].trim();m in t&&a.classList.toggle(w,!!t[m])}}return e}function Y(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)S(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function F(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const i=n.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,a){return t[a]!==void 0?t[a]:""}))}const o=function(i,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let i=0;i<r.length;i++){const l=r[i],a=l.attributes;for(let c=0;c<a.length;c++){const f=a[c];f.value.indexOf("{{")!==-1&&l.setAttribute(f.name,f.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function Z(e,t,n,o,r,i){const l={};for(let c=0;c<e.children.length;c++){const f=e.children[c],h=f.getAttribute("data-ln-render-key");h&&(l[h]=f)}const a=document.createDocumentFragment();for(let c=0;c<t.length;c++){const f=t[c],h=String(o(f));let w=l[h];if(w)r(w,f,c);else{const m=B(n,i);if(!m||(F(m,f),w=m.firstElementChild,!w))continue;w.setAttribute("data-ln-render-key",h),r(w,f,c)}a.appendChild(w)}e.textContent="",e.appendChild(a)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=F,window.lnCore.fill=S,window.lnCore.lnFill=Y,window.lnCore.renderList=Z);function R(e,t,n){const o=e.getAttribute(t);return o===null?n:o}function k(e,t,n){const o=parseInt(e.getAttribute(t),10);return isNaN(o)?n:o}function ee(e,t,n=!1){const o=e.getAttribute(t);if(o===null)return!!n;const r=o.trim().toLowerCase();return!(r==="false"||r==="0")}function te(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const E=new Map;function ne(e,t){const n=(e?e.join("|"):"")+"::"+t;if(E.has(n))return E.get(n);const o=new Set(e||[]),r=function(i,l){const a=i.getAttribute(l);return a!==null&&o.has(a)?a:t};return E.set(n,r),r}function oe(e,t,n){const o=parseFloat(e.getAttribute(t));return isNaN(o)?n:o}function re(e,t,n){const o=e.getAttribute(t);if(!o)return n;try{return JSON.parse(o)}catch{return n}}function j(e,t,n,o,r){if(!e||t===null)return!0;const i=o||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const a=c=>{r?console.warn(c,r):console.warn(c)};if(l==="boolean"){const c=t.trim().toLowerCase();return c!==""&&c!=="true"&&c!=="false"&&c!=="1"&&c!=="0"?(a(`[${i}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const c=e.values||[];return c.includes(t)?!0:(a(`[${i}] Invalid value "${t}" for attribute "${n}". Allowed: ${c.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return a(`[${i}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const c=parseInt(t,10);return e.min!==void 0&&c<e.min?(a(`[${i}] Value ${c} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&c>e.max?(a(`[${i}] Value ${c} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(a(`[${i}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(c){return a(`[${i}] Invalid JSON for attribute "${n}": ${c.message}. Fallback: ${e.fallback}.`),!1}return!0}function ie(e,t,n){for(const o in n){const[r,i,l]=n[o];Object.defineProperty(e,o,{get:function(){return r(t,i,l)},enumerable:!0,configurable:!0})}return e}function le(e){const t={};for(const n in e){const o=e[n];if(!o||!o.prop)continue;let r=o.read;if(!r&&o.type)switch(o.type){case"enum":r=ne(o.values,o.fallback);break;case"integer":r=k;break;case"float":r=oe;break;case"boolean":r=ee;break;case"list":r=te;break;case"json":r=re;break;case"string":default:r=R;break}r||(r=R),t[o.prop]=[r,n,o.fallback]}return t}function se(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function ae(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function L(e,t,n,o){if(e.nodeType!==1)return;const i=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l=Array.from(e.querySelectorAll(i));e.matches&&e.matches(i)&&l.push(e);for(const a of l)if(!a[n]){window.lnCore._persistSink&&a.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(a,t);try{a[n]=new o(a)}catch(c){console.error("["+n+"] init failed",a,c)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function ce(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function ue(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function W(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function de(e){const t=W(),n=e.observed||[];for(let o=0;o<n.length;o++){const r=n[o];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const r=t.byDeclaredAttr.get(o);r.some(i=>i.componentTag===e.componentTag)||r.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=ae(e);if(o===null)t.reactiveWildcard.push(e);else for(const r of o)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function H(e,t,n,o){for(let r=0;r<e.length;r++){const i=e[r];if(!t[i.attribute])continue;const l=i.effects&&i.effects[n];l?l(t,n,o):i.onAttrChange&&(!i.declared||i.declared.has(n))&&i.onAttrChange(t,n,o)}}function fe(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=W(),r=o.byAttr.get(n);if($()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&_(t)){const i=o.byDeclaredAttr.get(n),l=t.getAttribute(n);for(let a=0;a<i.length;a++)j(i[a].spec,l,n,i[a].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||r)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const i=o.byReactive.get(n);i&&H(i,t,n,e.oldValue),o.reactiveWildcard.length&&H(o.reactiveWildcard,t,n,e.oldValue)}if(r)for(let i=0;i<r.length;i++){const l=r[i];if(l.handler){l.handler(t,n,e.oldValue);continue}l.onAttributeChange&&t[l.attribute]?l.onAttributeChange(t,n):(L(t,l.selector,l.attribute,l.ComponentFn),l.onInit&&l.onInit(t))}}function we(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{fe(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function V(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function he(e){const t=V();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const r=o.query,i=e.target.nodeType===1?e.target.matches(r)?e.target:e.target.closest(r):e.target.parentElement?e.target.parentElement.closest(r):null;i&&o.onSubtreeChange(i,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r];L(o,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r],l=i.query,a=Array.from(o.querySelectorAll(l));o.matches&&o.matches(l)&&a.push(o);for(let c=0;c<a.length;c++){const f=a[c];if(!document.contains(f)){const h=f[i.attribute];if(h&&typeof h.destroy=="function")try{h.destroy()}catch(w){console.error("["+i.attribute+"] destroy failed",f,w)}delete f[i.attribute]}}}}}}function pe(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{he(o)}catch(r){console.error("[ln-core] lifecycle handler failed",o.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function be(e,t,n,o,r={}){const i=r.extraAttributes||[],l=r.onAttributeChange||null,a=r.onSubtreeChange||null,c=r.onInit||null,f=r.onAttrChange||null,h=r.effects||null,w=r.attributes||null,m=w?se(w):h,O=w?new Set(Object.keys(w)):null,x=r.persist||null;function C(b){const g=b||document.body;if(L(g,e,t,n),w&&$())for(const y in w){const ke=w[y],q=Array.from(g.querySelectorAll("["+y+"]"));g.matches&&g.matches("["+y+"]")&&q.push(g);for(let I=0;I<q.length;I++){const D=q[I];_(D)&&j(ke,D.getAttribute(y),y,o,D)}}c&&c(g)}const s=[];if(e.indexOf("[")!==-1){const b=/\[([\w-]+)/g;let g;for(;(g=b.exec(e))!==null;)s.push(g[1])}else s.push(e);de({selector:e,attribute:t,componentTag:o,attributes:w,ComponentFn:n,onInit:c,observed:s.concat(i),onAttributeChange:l,onAttrChange:f,effects:m,declared:O,persist:x}),we();const d=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";V().push({selector:e,attribute:t,ComponentFn:n,onInit:c,onSubtreeChange:a,query:d}),pe(),window[t]=C;function p(){ce()>0?ue(function(){C(document.body)}):C(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p(),C}function P(e){return(e||"").replace(/^#/,"")}function T(e){const t=e===void 0?location.hash:e,n={},o=P(t);if(!o)return n;const r=o.split("&");for(let i=0;i<r.length;i++){const l=r[i];if(!l)continue;const a=l.indexOf(":"),c=a>-1?l.slice(0,a):l,f=a>-1?l.slice(a+1):"";if(c)try{n[c]=decodeURIComponent(f)}catch{n[c]=f}}return n}function me(e){if(!e)return null;const t=T();return e in t?t[e]:null}function ge(e,t){if(!e)return;const n=T();t==null?delete n[e]:n[e]=String(t);const r=Object.keys(n).map(function(i){const l=n[i];return l===""?i:i+":"+encodeURIComponent(l)}).join("&");P(location.hash)!==r&&(location.hash=r)}function ye(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Ce(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function Ae(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function _e(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ve(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Se(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),r=o?o.split(",").map(function(i){try{return decodeURIComponent(i)}catch{return i}}).filter(Boolean):[];return{key:n,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=T,window.lnCore.hashGet=me,window.lnCore.hashSet=ge,window.lnCore.hashLinkClick=ye,window.lnCore.resolveHashNamespace=Ce,window.lnCore.hashSortEncode=Ae,window.lnCore.hashSortDecode=_e,window.lnCore.hashFilterEncode=ve,window.lnCore.hashFilterDecode=Se),(function(){const e="data-ln-toast",t="lnToast",n="ln-toast-item";if(window[t]!==void 0)return;const o={"data-ln-toast":{type:"marker",description:"Initializes the toast notifications container"},"data-ln-toast-timeout":{prop:"timeoutDefault",type:"integer",read:k,fallback:6e3,min:500,description:"Default auto-dismiss timeout in ms"},"data-ln-toast-max":{prop:"max",type:"integer",read:k,fallback:5,min:1,description:"Maximum visible concurrent toast notifications"},"data-ln-toast-close":{type:"trigger",description:"Click dismiss trigger inside a toast item"},"data-ln-toast-item":{type:"marker",description:"Individual toast notification element"}},r=le(o);function i(s){if(!(!s||!(s instanceof HTMLElement))&&(s.hasAttribute("popover")||s.setAttribute("popover","manual"),typeof s.showPopover=="function")){if(s.matches(":popover-open"))try{s.hidePopover()}catch{}try{s.showPopover()}catch{}}}function l(s){if(!s||!(s instanceof HTMLElement))return;if(s.querySelectorAll("[data-ln-toast-item]").length===0&&typeof s.hidePopover=="function"&&s.matches(":popover-open"))try{s.hidePopover()}catch{}}function a(s){this.dom=s,ie(this,s,r);const u=Array.from(s.querySelectorAll("[data-ln-toast-item]"));for(;u.length>this.max;)s.removeChild(u.shift());for(const d of u)O(d,this);return u.length>0&&i(s),this}a.prototype.enqueue=function(s){if(!s)return;const u=c(s,this.dom);if(!u)return;const d=Number.isFinite(s.timeout)?s.timeout:this.timeoutDefault;h(this,u),d>0&&(u._timer=setTimeout(()=>w(u),d))},a.prototype.clear=function(){for(const s of Array.from(this.dom.querySelectorAll("[data-ln-toast-item]")))w(s)},a.prototype.destroy=function(){if(this.dom[t]){for(const s of Array.from(this.dom.querySelectorAll("[data-ln-toast-item]")))w(s);l(this.dom),delete this.dom[t]}};function c(s,u){const d=((s.type||"")+"").trim().toLowerCase(),p=X(u,n,"ln-toast");if(!p)return console.warn('[ln-toast] Template "'+n+'" not found'),null;S(p,{type:d,title:s.title,message:typeof s.message=="string"?s.message:void 0});const b=p.firstElementChild;if(!b)return null;b.hasAttribute("data-ln-toast-item")||b.setAttribute("data-ln-toast-item",""),b.classList.add("ln-enter");const g=b.querySelector(".body");g&&f(g,s);const y=b.querySelector("[data-ln-toast-close]");return y&&y.addEventListener("click",function(){w(b)}),b}function f(s,u){if(Array.isArray(u.message)){const d=document.createElement("ul");for(const p of u.message){const b=document.createElement("li");b.textContent=p,d.appendChild(b)}s.appendChild(d)}if(u.data&&u.data.errors){const d=document.createElement("ul");for(const p of Object.values(u.data.errors).flat()){const b=document.createElement("li");b.textContent=p,d.appendChild(b)}s.appendChild(d)}}function h(s,u){const d=Array.from(s.dom.querySelectorAll("[data-ln-toast-item]"));for(;d.length>=s.max&&d.length>0;)s.dom.removeChild(d.shift());s.dom.appendChild(u),i(s.dom),requestAnimationFrame(()=>u.classList.remove("ln-enter"))}function w(s){if(!s||!s.parentNode)return;const u=s.parentNode;clearTimeout(s._timer),s.classList.remove("ln-enter"),s.classList.add("ln-out"),setTimeout(()=>{s.parentNode&&(s.parentNode.removeChild(s),l(u))},200)}function m(s){let u=s&&s.container;return typeof u=="string"&&(u=document.querySelector(u)),u instanceof HTMLElement||(u=document.querySelector("["+e+"]")||document.getElementById("ln-toast-container")),u||null}function O(s,u){if(s._lnToastHydrated)return;s._lnToastHydrated=!0;const d=s.querySelector("[data-ln-toast-close]");d&&d.addEventListener("click",function(){w(s)});const p=+(s.getAttribute("data-ln-toast-timeout")??u.timeoutDefault);p>0&&(s._timer=setTimeout(function(){w(s)},p))}function x(s){const u=s.detail||{},d=m(u);if(!d){console.warn("[ln-toast] No toast container found");return}(d[t]||(d[t]=new a(d))).enqueue(u)}function C(s){const u=s&&s.detail||{};if(u.container){const d=m(u);d&&(d[t]||(d[t]=new a(d))).clear()}else{const d=document.querySelectorAll("["+e+"]");for(const p of Array.from(d))(p[t]||(p[t]=new a(p))).clear()}}A(function(){window.addEventListener("ln-toast:enqueue",x),window.addEventListener("ln-toast:clear",C),window.addEventListener("ln-modal:open",function(){const s=document.querySelectorAll("["+e+"], #ln-toast-container");for(const u of Array.from(s))u.querySelectorAll("[data-ln-toast-item]").length>0&&i(u)})},"ln-toast"),be(e,t,a,"ln-toast",{attributes:o})})()})();
@@ -3,9 +3,13 @@
3
3
  // ==========================================================================
4
4
 
5
5
  [data-ln-toast] {
6
+ position: fixed;
7
+ z-index: var(--z-toast, 50);
8
+ inset: auto;
9
+ right: var(--size-lg, 1.5rem);
10
+ bottom: var(--size-lg, 1.5rem);
6
11
  border: none;
7
12
  background: transparent;
8
- inset: auto;
9
13
  list-style: none;
10
14
  padding: 0;
11
15
  margin: 0;
@@ -218,7 +218,7 @@ import { guardBody, cloneTemplateScoped, fill, registerComponent, defineAttrs, a
218
218
  window.addEventListener('ln-toast:enqueue', _onEnqueue);
219
219
  window.addEventListener('ln-toast:clear', _onClear);
220
220
  window.addEventListener('ln-modal:open', function () {
221
- const containers = document.querySelectorAll("[" + DOM_SELECTOR + "]");
221
+ const containers = document.querySelectorAll("[" + DOM_SELECTOR + "], #ln-toast-container");
222
222
  for (const container of Array.from(containers)) {
223
223
  if (container.querySelectorAll("[data-ln-toast-item]").length > 0) {
224
224
  _promoteTopLayer(container);
@@ -1054,6 +1054,10 @@
1054
1054
  "name": "data-ln-route-title",
1055
1055
  "description": "Document title template set when route is activated"
1056
1056
  },
1057
+ {
1058
+ "name": "data-ln-router-base",
1059
+ "description": "Base URL prefix for subdirectory routing (e.g. "
1060
+ },
1057
1061
  {
1058
1062
  "name": "data-ln-router-hydrate",
1059
1063
  "description": "Hydrate existing DOM content on initial router boot",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livenetworks/ashlar",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "LiveNetworks unified frontend library - CSS framework and vanilla JS components",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Live Networks",
package/web-types.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@livenetworks/ashlar",
4
- "version": "2.0.2",
4
+ "version": "2.0.4",
5
5
  "framework": "html",
6
6
  "contributions": {
7
7
  "html": {
@@ -1337,6 +1337,13 @@
1337
1337
  "type": "string"
1338
1338
  }
1339
1339
  },
1340
+ {
1341
+ "name": "data-ln-router-base",
1342
+ "description": "Base URL prefix for subdirectory routing (e.g. ",
1343
+ "value": {
1344
+ "type": "string"
1345
+ }
1346
+ },
1340
1347
  {
1341
1348
  "name": "data-ln-router-hydrate",
1342
1349
  "description": "Hydrate existing DOM content on initial router boot",