@livenetworks/ashlar 2.2.0 → 2.2.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 (353) hide show
  1. package/assets/brand/android-chrome-192x192.png +0 -0
  2. package/assets/brand/android-chrome-512x512.png +0 -0
  3. package/assets/brand/apple-touch-icon.png +0 -0
  4. package/assets/brand/favicon-16x16.png +0 -0
  5. package/assets/brand/favicon-32x32.png +0 -0
  6. package/assets/brand/favicon-48x48.png +0 -0
  7. package/assets/brand/favicon-dark-128x128.png +0 -0
  8. package/assets/brand/favicon-dark-16x16.png +0 -0
  9. package/assets/brand/favicon-dark-180x180.png +0 -0
  10. package/assets/brand/favicon-dark-192x192.png +0 -0
  11. package/assets/brand/favicon-dark-256x256.png +0 -0
  12. package/assets/brand/favicon-dark-32x32.png +0 -0
  13. package/assets/brand/favicon-dark-48x48.png +0 -0
  14. package/assets/brand/favicon-dark-512x512.png +0 -0
  15. package/assets/brand/favicon-dark-64x64.png +0 -0
  16. package/assets/brand/favicon-dark.ico +0 -0
  17. package/assets/brand/favicon-dark.png +0 -0
  18. package/assets/brand/favicon-light-128x128.png +0 -0
  19. package/assets/brand/favicon-light-16x16.png +0 -0
  20. package/assets/brand/favicon-light-180x180.png +0 -0
  21. package/assets/brand/favicon-light-192x192.png +0 -0
  22. package/assets/brand/favicon-light-256x256.png +0 -0
  23. package/assets/brand/favicon-light-32x32.png +0 -0
  24. package/assets/brand/favicon-light-48x48.png +0 -0
  25. package/assets/brand/favicon-light-512x512.png +0 -0
  26. package/assets/brand/favicon-light-64x64.png +0 -0
  27. package/assets/brand/favicon-light.ico +0 -0
  28. package/assets/brand/favicon-light.png +0 -0
  29. package/assets/brand/favicon.ico +0 -0
  30. package/assets/brand/favicon.png +0 -0
  31. package/assets/brand/favicon.svg +12 -0
  32. package/assets/brand/ln-ashlar-emblem-dark-128.png +0 -0
  33. package/assets/brand/ln-ashlar-emblem-dark-16.png +0 -0
  34. package/assets/brand/ln-ashlar-emblem-dark-256.png +0 -0
  35. package/assets/brand/ln-ashlar-emblem-dark-32.png +0 -0
  36. package/assets/brand/ln-ashlar-emblem-dark-64.png +0 -0
  37. package/assets/brand/ln-ashlar-emblem-dark.png +0 -0
  38. package/assets/brand/ln-ashlar-emblem-light-128.png +0 -0
  39. package/assets/brand/ln-ashlar-emblem-light-16.png +0 -0
  40. package/assets/brand/ln-ashlar-emblem-light-256.png +0 -0
  41. package/assets/brand/ln-ashlar-emblem-light-32.png +0 -0
  42. package/assets/brand/ln-ashlar-emblem-light-64.png +0 -0
  43. package/assets/brand/ln-ashlar-emblem-light.png +0 -0
  44. package/assets/brand/ln-ashlar-logo-dark-128.png +0 -0
  45. package/assets/brand/ln-ashlar-logo-dark-256.png +0 -0
  46. package/assets/brand/ln-ashlar-logo-dark-512.png +0 -0
  47. package/assets/brand/ln-ashlar-logo-dark.png +0 -0
  48. package/assets/brand/ln-ashlar-logo-light-128.png +0 -0
  49. package/assets/brand/ln-ashlar-logo-light-256.png +0 -0
  50. package/assets/brand/ln-ashlar-logo-light-512.png +0 -0
  51. package/assets/brand/ln-ashlar-logo-light.png +0 -0
  52. package/assets/brand/site.webmanifest +41 -0
  53. package/assets/brand/source/ln-ashlar-icon-dark-1024.png +0 -0
  54. package/assets/brand/source/ln-ashlar-icon-dark-uncropped-1024.png +0 -0
  55. package/assets/brand/source/ln-ashlar-icon-light-1024.png +0 -0
  56. package/assets/brand/source/ln-ashlar-icon-light-uncropped-1024.png +0 -0
  57. package/assets/flags/ad.svg +150 -0
  58. package/assets/flags/ae.svg +6 -0
  59. package/assets/flags/af.svg +81 -0
  60. package/assets/flags/ag.svg +14 -0
  61. package/assets/flags/ai.svg +29 -0
  62. package/assets/flags/al.svg +5 -0
  63. package/assets/flags/am.svg +5 -0
  64. package/assets/flags/ao.svg +13 -0
  65. package/assets/flags/aq.svg +5 -0
  66. package/assets/flags/ar.svg +32 -0
  67. package/assets/flags/arab.svg +109 -0
  68. package/assets/flags/as.svg +72 -0
  69. package/assets/flags/asean.svg +13 -0
  70. package/assets/flags/at.svg +4 -0
  71. package/assets/flags/au.svg +8 -0
  72. package/assets/flags/aw.svg +186 -0
  73. package/assets/flags/ax.svg +18 -0
  74. package/assets/flags/az.svg +8 -0
  75. package/assets/flags/ba.svg +12 -0
  76. package/assets/flags/bb.svg +6 -0
  77. package/assets/flags/bd.svg +4 -0
  78. package/assets/flags/be.svg +7 -0
  79. package/assets/flags/bf.svg +7 -0
  80. package/assets/flags/bg.svg +5 -0
  81. package/assets/flags/bh.svg +4 -0
  82. package/assets/flags/bi.svg +15 -0
  83. package/assets/flags/bj.svg +14 -0
  84. package/assets/flags/bl.svg +5 -0
  85. package/assets/flags/bm.svg +97 -0
  86. package/assets/flags/bn.svg +36 -0
  87. package/assets/flags/bo.svg +673 -0
  88. package/assets/flags/bq.svg +5 -0
  89. package/assets/flags/br.svg +45 -0
  90. package/assets/flags/bs.svg +13 -0
  91. package/assets/flags/bt.svg +89 -0
  92. package/assets/flags/bv.svg +13 -0
  93. package/assets/flags/bw.svg +7 -0
  94. package/assets/flags/by.svg +18 -0
  95. package/assets/flags/bz.svg +145 -0
  96. package/assets/flags/ca.svg +4 -0
  97. package/assets/flags/cc.svg +19 -0
  98. package/assets/flags/cd.svg +5 -0
  99. package/assets/flags/cefta.svg +13 -0
  100. package/assets/flags/cf.svg +15 -0
  101. package/assets/flags/cg.svg +12 -0
  102. package/assets/flags/ch.svg +9 -0
  103. package/assets/flags/ci.svg +7 -0
  104. package/assets/flags/ck.svg +9 -0
  105. package/assets/flags/cl.svg +13 -0
  106. package/assets/flags/cm.svg +15 -0
  107. package/assets/flags/cn.svg +11 -0
  108. package/assets/flags/co.svg +7 -0
  109. package/assets/flags/cp.svg +7 -0
  110. package/assets/flags/cr.svg +7 -0
  111. package/assets/flags/cu.svg +13 -0
  112. package/assets/flags/cv.svg +13 -0
  113. package/assets/flags/cw.svg +14 -0
  114. package/assets/flags/cx.svg +15 -0
  115. package/assets/flags/cy.svg +6 -0
  116. package/assets/flags/cz.svg +5 -0
  117. package/assets/flags/de.svg +5 -0
  118. package/assets/flags/dg.svg +130 -0
  119. package/assets/flags/dj.svg +13 -0
  120. package/assets/flags/dk.svg +5 -0
  121. package/assets/flags/dm.svg +152 -0
  122. package/assets/flags/do.svg +121 -0
  123. package/assets/flags/dz.svg +5 -0
  124. package/assets/flags/eac.svg +48 -0
  125. package/assets/flags/ec.svg +138 -0
  126. package/assets/flags/ee.svg +5 -0
  127. package/assets/flags/eg.svg +38 -0
  128. package/assets/flags/eh.svg +16 -0
  129. package/assets/flags/er.svg +8 -0
  130. package/assets/flags/es-ct.svg +4 -0
  131. package/assets/flags/es-ga.svg +187 -0
  132. package/assets/flags/es-pv.svg +5 -0
  133. package/assets/flags/es.svg +544 -0
  134. package/assets/flags/et.svg +14 -0
  135. package/assets/flags/eu.svg +28 -0
  136. package/assets/flags/fi.svg +5 -0
  137. package/assets/flags/fj.svg +120 -0
  138. package/assets/flags/fk.svg +90 -0
  139. package/assets/flags/fm.svg +11 -0
  140. package/assets/flags/fo.svg +12 -0
  141. package/assets/flags/fr.svg +5 -0
  142. package/assets/flags/ga.svg +7 -0
  143. package/assets/flags/gb-eng.svg +5 -0
  144. package/assets/flags/gb-nir.svg +132 -0
  145. package/assets/flags/gb-sct.svg +4 -0
  146. package/assets/flags/gb-wls.svg +9 -0
  147. package/assets/flags/gb.svg +7 -0
  148. package/assets/flags/gd.svg +27 -0
  149. package/assets/flags/ge.svg +6 -0
  150. package/assets/flags/gf.svg +5 -0
  151. package/assets/flags/gg.svg +9 -0
  152. package/assets/flags/gh.svg +6 -0
  153. package/assets/flags/gi.svg +32 -0
  154. package/assets/flags/gl.svg +4 -0
  155. package/assets/flags/gm.svg +14 -0
  156. package/assets/flags/gn.svg +7 -0
  157. package/assets/flags/gp.svg +5 -0
  158. package/assets/flags/gq.svg +23 -0
  159. package/assets/flags/gr.svg +16 -0
  160. package/assets/flags/gs.svg +133 -0
  161. package/assets/flags/gt.svg +204 -0
  162. package/assets/flags/gu.svg +19 -0
  163. package/assets/flags/gw.svg +13 -0
  164. package/assets/flags/gy.svg +9 -0
  165. package/assets/flags/hk.svg +8 -0
  166. package/assets/flags/hm.svg +8 -0
  167. package/assets/flags/hn.svg +18 -0
  168. package/assets/flags/hr.svg +58 -0
  169. package/assets/flags/ht.svg +116 -0
  170. package/assets/flags/hu.svg +7 -0
  171. package/assets/flags/ic.svg +7 -0
  172. package/assets/flags/id.svg +4 -0
  173. package/assets/flags/ie.svg +7 -0
  174. package/assets/flags/il.svg +14 -0
  175. package/assets/flags/im.svg +36 -0
  176. package/assets/flags/in.svg +25 -0
  177. package/assets/flags/io.svg +130 -0
  178. package/assets/flags/iq.svg +10 -0
  179. package/assets/flags/ir.svg +219 -0
  180. package/assets/flags/is.svg +12 -0
  181. package/assets/flags/it.svg +7 -0
  182. package/assets/flags/je.svg +62 -0
  183. package/assets/flags/jm.svg +8 -0
  184. package/assets/flags/jo.svg +16 -0
  185. package/assets/flags/jp.svg +11 -0
  186. package/assets/flags/ke.svg +23 -0
  187. package/assets/flags/kg.svg +4 -0
  188. package/assets/flags/kh.svg +61 -0
  189. package/assets/flags/ki.svg +36 -0
  190. package/assets/flags/km.svg +16 -0
  191. package/assets/flags/kn.svg +14 -0
  192. package/assets/flags/kp.svg +15 -0
  193. package/assets/flags/kr.svg +24 -0
  194. package/assets/flags/kw.svg +13 -0
  195. package/assets/flags/ky.svg +103 -0
  196. package/assets/flags/kz.svg +36 -0
  197. package/assets/flags/la.svg +12 -0
  198. package/assets/flags/lb.svg +15 -0
  199. package/assets/flags/lc.svg +8 -0
  200. package/assets/flags/li.svg +43 -0
  201. package/assets/flags/lk.svg +22 -0
  202. package/assets/flags/lr.svg +14 -0
  203. package/assets/flags/ls.svg +8 -0
  204. package/assets/flags/lt.svg +7 -0
  205. package/assets/flags/lu.svg +5 -0
  206. package/assets/flags/lv.svg +6 -0
  207. package/assets/flags/ly.svg +13 -0
  208. package/assets/flags/ma.svg +4 -0
  209. package/assets/flags/mc.svg +6 -0
  210. package/assets/flags/md.svg +70 -0
  211. package/assets/flags/me.svg +116 -0
  212. package/assets/flags/mf.svg +5 -0
  213. package/assets/flags/mg.svg +7 -0
  214. package/assets/flags/mh.svg +7 -0
  215. package/assets/flags/mk.svg +5 -0
  216. package/assets/flags/ml.svg +7 -0
  217. package/assets/flags/mm.svg +12 -0
  218. package/assets/flags/mn.svg +14 -0
  219. package/assets/flags/mo.svg +9 -0
  220. package/assets/flags/mp.svg +86 -0
  221. package/assets/flags/mq.svg +5 -0
  222. package/assets/flags/mr.svg +6 -0
  223. package/assets/flags/ms.svg +29 -0
  224. package/assets/flags/mt.svg +58 -0
  225. package/assets/flags/mu.svg +8 -0
  226. package/assets/flags/mv.svg +6 -0
  227. package/assets/flags/mw.svg +10 -0
  228. package/assets/flags/mx.svg +382 -0
  229. package/assets/flags/my.svg +26 -0
  230. package/assets/flags/mz.svg +21 -0
  231. package/assets/flags/na.svg +16 -0
  232. package/assets/flags/nc.svg +13 -0
  233. package/assets/flags/ne.svg +6 -0
  234. package/assets/flags/nf.svg +9 -0
  235. package/assets/flags/ng.svg +6 -0
  236. package/assets/flags/ni.svg +129 -0
  237. package/assets/flags/nl.svg +5 -0
  238. package/assets/flags/no.svg +7 -0
  239. package/assets/flags/np.svg +13 -0
  240. package/assets/flags/nr.svg +12 -0
  241. package/assets/flags/nu.svg +10 -0
  242. package/assets/flags/nz.svg +36 -0
  243. package/assets/flags/om.svg +115 -0
  244. package/assets/flags/pa.svg +14 -0
  245. package/assets/flags/pc.svg +33 -0
  246. package/assets/flags/pe.svg +4 -0
  247. package/assets/flags/pf.svg +19 -0
  248. package/assets/flags/pg.svg +9 -0
  249. package/assets/flags/ph.svg +6 -0
  250. package/assets/flags/pk.svg +15 -0
  251. package/assets/flags/pl.svg +6 -0
  252. package/assets/flags/pm.svg +5 -0
  253. package/assets/flags/pn.svg +53 -0
  254. package/assets/flags/pr.svg +13 -0
  255. package/assets/flags/ps.svg +6 -0
  256. package/assets/flags/pt.svg +57 -0
  257. package/assets/flags/pw.svg +11 -0
  258. package/assets/flags/py.svg +157 -0
  259. package/assets/flags/qa.svg +4 -0
  260. package/assets/flags/re.svg +5 -0
  261. package/assets/flags/ro.svg +7 -0
  262. package/assets/flags/rs.svg +292 -0
  263. package/assets/flags/ru.svg +5 -0
  264. package/assets/flags/rw.svg +13 -0
  265. package/assets/flags/sa.svg +25 -0
  266. package/assets/flags/sb.svg +13 -0
  267. package/assets/flags/sc.svg +7 -0
  268. package/assets/flags/sd.svg +13 -0
  269. package/assets/flags/se.svg +4 -0
  270. package/assets/flags/sg.svg +13 -0
  271. package/assets/flags/sh-ac.svg +689 -0
  272. package/assets/flags/sh-hl.svg +164 -0
  273. package/assets/flags/sh-ta.svg +76 -0
  274. package/assets/flags/sh.svg +7 -0
  275. package/assets/flags/si.svg +18 -0
  276. package/assets/flags/sj.svg +7 -0
  277. package/assets/flags/sk.svg +9 -0
  278. package/assets/flags/sl.svg +7 -0
  279. package/assets/flags/sm.svg +75 -0
  280. package/assets/flags/sn.svg +8 -0
  281. package/assets/flags/so.svg +11 -0
  282. package/assets/flags/sr.svg +6 -0
  283. package/assets/flags/ss.svg +8 -0
  284. package/assets/flags/st.svg +16 -0
  285. package/assets/flags/sv.svg +593 -0
  286. package/assets/flags/sx.svg +56 -0
  287. package/assets/flags/sy.svg +6 -0
  288. package/assets/flags/sz.svg +34 -0
  289. package/assets/flags/tc.svg +50 -0
  290. package/assets/flags/td.svg +7 -0
  291. package/assets/flags/tf.svg +15 -0
  292. package/assets/flags/tg.svg +14 -0
  293. package/assets/flags/th.svg +7 -0
  294. package/assets/flags/tj.svg +22 -0
  295. package/assets/flags/tk.svg +5 -0
  296. package/assets/flags/tl.svg +13 -0
  297. package/assets/flags/tm.svg +204 -0
  298. package/assets/flags/tn.svg +4 -0
  299. package/assets/flags/to.svg +10 -0
  300. package/assets/flags/tr.svg +8 -0
  301. package/assets/flags/tt.svg +5 -0
  302. package/assets/flags/tv.svg +9 -0
  303. package/assets/flags/tw.svg +34 -0
  304. package/assets/flags/tz.svg +13 -0
  305. package/assets/flags/ua.svg +6 -0
  306. package/assets/flags/ug.svg +30 -0
  307. package/assets/flags/um.svg +9 -0
  308. package/assets/flags/un.svg +16 -0
  309. package/assets/flags/us.svg +9 -0
  310. package/assets/flags/uy.svg +28 -0
  311. package/assets/flags/uz.svg +30 -0
  312. package/assets/flags/va.svg +190 -0
  313. package/assets/flags/vc.svg +8 -0
  314. package/assets/flags/ve.svg +26 -0
  315. package/assets/flags/vg.svg +59 -0
  316. package/assets/flags/vi.svg +28 -0
  317. package/assets/flags/vn.svg +11 -0
  318. package/assets/flags/vu.svg +21 -0
  319. package/assets/flags/wf.svg +5 -0
  320. package/assets/flags/ws.svg +7 -0
  321. package/assets/flags/xk.svg +5 -0
  322. package/assets/flags/xx.svg +4 -0
  323. package/assets/flags/ye.svg +7 -0
  324. package/assets/flags/yt.svg +5 -0
  325. package/assets/flags/za.svg +17 -0
  326. package/assets/flags/zm.svg +27 -0
  327. package/assets/flags/zw.svg +21 -0
  328. package/components/ln-data-coordinator/ln-data-coordinator.js +1 -1
  329. package/components/ln-date/ln-date.js +1 -1
  330. package/components/ln-debug/ln-debug.js +1 -1
  331. package/components/ln-debug/src/generated-attributes.js +306 -304
  332. package/components/ln-external-links/ln-external-links.js +1 -1
  333. package/components/ln-filter/ln-filter.js +1 -1
  334. package/components/ln-obfuscator/ln-obfuscator.js +1 -1
  335. package/components/ln-sort/ln-sort.js +1 -1
  336. package/components/ln-table/ln-table.js +1 -1
  337. package/components/ln-table-coordinator/ln-table-coordinator.js +1 -1
  338. package/components/ln-toast/ln-toast.js +1 -1
  339. package/components/ln-translations/README.md +202 -120
  340. package/components/ln-translations/ln-translations.js +1 -1
  341. package/components/ln-translations/ln-translations.schema.json +136 -120
  342. package/components/ln-translations/src/ln-translations.js +354 -295
  343. package/components/ln-translations/src/translations-model.js +221 -0
  344. package/components/ln-validate/ln-validate.js +1 -1
  345. package/ln-ashlar.html-data.json +1832 -1824
  346. package/package.json +96 -95
  347. package/theme/components/_translations.scss +118 -111
  348. package/theme/config/mixins/_app-shell.scss +14 -0
  349. package/theme/config/mixins/_count.scss +48 -0
  350. package/theme/config/mixins/_index.scss +1 -0
  351. package/theme/config/mixins/_nav.scss +3 -11
  352. package/theme/config/mixins/_translations.scss +126 -124
  353. package/web-types.json +2365 -2351
@@ -1,120 +1,202 @@
1
- # ln-translations
2
-
3
- > Applied to a form element (`<form data-ln-translations data-ln-translations-default="en">`). It coordinates translatable input containers (`[data-ln-translatable="field"]`), dynamically cloning the inner form controls with deterministic nested names (`trans[lang][field]`) when languages are added, and synchronizes active language badges and dropdown menus via `<template>` elements. It manages no network transport or validation, submitting cloned fields natively through the standard `<form>` submission pipeline.
4
-
5
- A zero-dependency, event-driven **Form Translation Coordinator** that manages inline multi-lingual inputs by dynamically cloning translatable fields on-demand.
6
-
7
- Instead of writing custom layout handlers to manage multi-language fields, this component intercepts locale additions and removals, duplicates translatable fields with appropriate naming conventions, and handles pre-rendered server payloads automatically.
8
-
9
- ---
10
-
11
- ## 🧭 Philosophy & Architecture
12
-
13
- 1. **Inline Field Cloning:** Translatable containers carrying `data-ln-translatable="field"` are treated as templates. When a language is activated, the coordinator clones the inner input/textarea/select, binds the target language value, and appends it beneath the original.
14
- 2. **Deterministic Name Generation:** To support clean form submission, cloned inputs automatically update their name attribute following standard nested arrays:
15
- - **Default Name**: `scope` becomes `trans[en][scope]` for English.
16
- - **Nested Name**: `items[5][title]` with prefix `items[5]` becomes `items[5][trans][en][title]`.
17
- 3. **Menu & Badge Coordination:** It coordinates locale-selector dropdowns and active language indicator badges using native HTML `<template>` nodes, keeping visual UI elements synchronized in real-time.
18
- 4. **Server-Rendered Auto-Detection:** If the server pre-renders localized fields with `data-ln-translatable-lang="{lang}"` on page load, the coordinator auto-detects and integrates them instantly.
19
-
20
- ---
21
-
22
- ## 📦 Minimal Blueprint
23
-
24
- ### Translatable Form Structure
25
- ```html
26
- <form data-ln-translations data-ln-translations-default="en">
27
- <header class="ln-translations__header">
28
- <h3>Form Content</h3>
29
- <!-- Active Language Badges -->
30
- <ul data-ln-translations-active></ul>
31
- <!-- Locale Add Menu (Dropdown coordinated) -->
32
- <div data-ln-dropdown>
33
- <button type="button" data-ln-translations-add data-ln-toggle-for="trans-menu">
34
- <svg class="ln-icon"><use href="#ln-icon-world"></use></svg>
35
- </button>
36
- <ul id="trans-menu" data-ln-toggle data-ln-dropdown-menu></ul>
37
- </div>
38
- </header>
39
-
40
- <main>
41
- <div data-ln-translatable="description">
42
- <label>Description <textarea name="description">Acme scope...</textarea></label>
43
- </div>
44
- </main>
45
- </form>
46
-
47
- <!-- REQUIRED GLOBAL TEMPLATES (Declared once before body closing) -->
48
- <template data-ln-template="ln-translations-badge">
49
- <li>
50
- <p data-ln-translations-lang>
51
- <span></span>
52
- <button type="button" aria-label="Remove"><svg class="ln-icon ln-icon--sm" aria-hidden="true"><use href="#ln-icon-x"></use></svg></button>
53
- </p>
54
- </li>
55
- </template>
56
- <template data-ln-template="ln-translations-menu-item">
57
- <li><button type="button" data-ln-translations-lang></button></li>
58
- </template>
59
- ```
60
-
61
- ---
62
-
63
- ## 🛠️ Declarative API Contract
64
-
65
- ### HTML Attributes
66
-
67
- | Attribute | Elements | Description |
68
- | :--- | :--- | :--- |
69
- | `data-ln-translations` | `<form>` | Component root. Initializes the translations coordinator. |
70
- | `data-ln-translations-default` | `<form>` | Default language code (e.g. `"en"`). Sets a flag on the original inputs. |
71
- | `data-ln-translations-locales` | `<form>` | Opt-in. Custom locales JSON list (e.g. `'{"en":"English", "de":"German"}'`). |
72
- | `data-ln-translations-add` | `<button>` | Trigger button inside `data-ln-dropdown` to open language menu. |
73
- | `data-ln-translations-active` | `<ul>` | Mount container where active language badges will be rendered. |
74
- | `data-ln-translations-placeholder` | `<form>` | Opt-in. Placeholder template for cloned inputs, e.g. `"{lang} translation"`. `{lang}` is replaced with the language display name. Default: `"{lang} translation"`. |
75
- | `data-ln-translations-remove-label` | `<form>` | Opt-in. `aria-label` template for the badge remove button, e.g. `"Remove {lang}"`. `{lang}` is replaced with the language display name. Default: `"Remove {lang}"`. |
76
- | `data-ln-translatable="field"` | Form field wrapper | Marks a translatable group. Value is the entity's field name. |
77
- | `data-ln-translations-prefix` | Form field wrapper | Opt-in. Naming prefix (e.g. `"items[1]"`) for nested form layouts. |
78
- | `data-ln-translatable-lang` | `<input>`, `<textarea>`, `<select>` | Language code identifying a cloned or pre-rendered translation input. |
79
-
80
- ---
81
-
82
- ## ⚡ DOM Events
83
-
84
- ### Telemetry (Dispatched by component)
85
- - **`ln-translations:before-add`** / **`ln-translations:before-remove`** (Cancelable)
86
- - Detail: `{ target, lang, langName }`
87
- - **`ln-translations:added`** / **`ln-translations:removed`**
88
- - Detail: `{ target, lang }`
89
-
90
- ### Commands (Dispatched to component)
91
- - **`ln-translations:request-add`** / **`ln-translations:request-remove`**
92
- - Detail: `{ lang: string }` (dispatched on the `<form>` to programmatically toggle languages).
93
-
94
- ---
95
-
96
- ## ⚠️ Common Pitfalls
97
-
98
- - **Forgetting Global Templates:** The coordinator will fail to render badges or locale dropdowns if `ln-translations-badge` and `ln-translations-menu-item` templates are missing from the page.
99
- - **Incorrect Translatable Wrappers:** `data-ln-translatable` must sit on the parent container (e.g. `<div data-ln-translatable="title">`) wrapping the default `<input>`/`<label>`, not on the input itself.
100
- - **Mismatched Prefixes:** When nesting entities (e.g., repeating list items), ensure the translatable wrapper declares the correct scope prefix: `data-ln-translations-prefix="items[index]"` to generate valid submission structures.
101
-
102
- ---
103
-
104
- ## 🔧 Internals
105
-
106
- Source: `components/ln-translations/ln-translations.js`. Instance state per `[data-ln-translations]` form (`form.lnTranslations`): `activeLanguages` (Set), `defaultLang`, `locales` map, `badgesEl`/`menuEl` refs, and the `placeholderLabel`/`removeLabel` templates (`{lang}` token).
107
-
108
- ### Add-language flow
109
-
110
- `addLanguage(lang, values)`: cancelable `:before-add` → add to `activeLanguages` → for every `[data-ln-translatable]` wrapper, clone the original input (deep clone for `<select>` to preserve its `<option>`s, shallow otherwise), rename to `prefix[trans][lang][field]` or `trans[lang][field]`, strip `id`, apply the placeholder template, tag `data-ln-translatable-lang`, insert after the last existing translation input for that field → rebuild the dropdown (only unactivated languages) and badges → `:added`.
111
-
112
- Original (default-language) inputs are tagged `data-ln-translatable-lang="{defaultLang}"` at init specifically so `removeLanguage` never matches and removes them.
113
-
114
- ### Remove-language flow
115
-
116
- `removeLanguage(lang)`: cancelable `:before-remove` → `querySelectorAll('[data-ln-translatable-lang="{lang}"]')` removed from DOM → delete from `activeLanguages` → rebuild dropdown/badges → `:removed`.
117
-
118
- ### MutationObserver
119
-
120
- A single shared observer (via `registerComponent`) watches `childList` for new `[data-ln-translations]` forms and `attributes` for the attribute landing on an existing element — no per-instance observer.
1
+ # ln-translations
2
+
3
+ > Applied to a form element (`<form data-ln-translations data-ln-translations-default="en">`). It coordinates translatable input containers (`[data-ln-translatable="field"]`), dynamically cloning the inner form controls with deterministic nested names (`trans[lang][field]`) when languages are added, and synchronizes active language badges and dropdown menus via `<template>` elements. It manages no network transport or validation, submitting cloned fields natively through the standard `<form>` submission pipeline.
4
+
5
+ A zero-dependency, event-driven **Form Translation Coordinator** that manages inline multi-lingual inputs by dynamically cloning translatable fields on-demand.
6
+
7
+ Instead of writing custom layout handlers to manage multi-language fields, this coordinator intercepts locale additions and removals, duplicates translatable fields with deterministic nested naming conventions, and handles pre-rendered server payloads automatically.
8
+
9
+ ---
10
+
11
+ ## 1. Core Behavior & Responsibility
12
+
13
+ - **Inline field cloning:** wraps translatable form fields via `data-ln-translatable`; when a language is activated (`addLanguage`), scans for translatable fields in the DOM, clones the wrapper's original `<input>`/`<textarea>`/`<select>` and appends the clone flagged with `data-ln-translatable-lang="{lang}"`.
14
+ - **Deterministic name generation:** cloned inputs get a nested array `name`, e.g. `trans[en][title]`, or `product[trans][en][title]` when the wrapper declares `data-ln-translations-prefix="product"`.
15
+ - **Menu & badge synchronization:** renders the available-language dropdown menu and the active-language badge list from two `<template>` elements (`ln-translations-menu-item`, `ln-translations-badge`), keeping both in sync on every add/remove.
16
+ - **Server-rendered hydration:** on init, scans the container for existing `[data-ln-translatable-lang]` elements and treats any language found there (other than the default) as already active, rebuilding the menu and badges accordingly — no `addLanguage()` call required.
17
+
18
+ The JavaScript source follows the Two-Tier Archetype: domain logic and algorithms are isolated in [translations-model.js](./src/translations-model.js), while the DOM coordinator shell is implemented in [ln-translations.js](./src/ln-translations.js).
19
+
20
+ > [!IMPORTANT]
21
+ > **What the component does NOT do (Orthogonality Doctrine):**
22
+ > - **Does NOT perform AJAX:** it only manipulates form fields in the DOM; submission is handled by the native `<form>` or `ln-form`.
23
+ > - **Does NOT open its own modals or dialogs:** the language menu is delegated to `ln-dropdown` + `ln-toggle`; the component never manages overlay state itself.
24
+ > - **Does NOT hardcode translatable field names or locale lists:** the active locales list is configurable via `data-ln-translations-locales` JSON or dictionary, and the translatable field names are declared via `data-ln-translatable` attributes.
25
+
26
+ ---
27
+
28
+ ## 2. Minimal HTML Markup & Usage Variants
29
+
30
+ ### Base HTML Markup
31
+
32
+ ```html
33
+ <form data-ln-translations data-ln-translations-default="en">
34
+ <header>
35
+ <h3>Company Info</h3>
36
+ <div class="ln-translations__actions">
37
+ <ul data-ln-translations-active></ul>
38
+ <div data-ln-dropdown>
39
+ <button type="button" data-ln-translations-add data-ln-toggle-for="trans-menu" aria-label="Add translation">
40
+ <svg class="ln-icon" aria-hidden="true"><use href="#ln-icon-world"></use></svg>
41
+ </button>
42
+ <ul id="trans-menu" data-ln-toggle></ul>
43
+ </div>
44
+ </div>
45
+ </header>
46
+
47
+ <main>
48
+ <div class="form-element">
49
+ <label for="company-name">Name</label>
50
+ <input type="text" id="company-name" name="name" value="Acme Corp">
51
+ </div>
52
+
53
+ <div class="form-element" data-ln-translatable="tagline">
54
+ <label for="company-tagline">Tagline</label>
55
+ <input type="text" id="company-tagline" name="tagline" value="Quality since 1990">
56
+ </div>
57
+
58
+ <div class="form-element" data-ln-translatable="scope" data-ln-translations-prefix="company">
59
+ <label for="company-scope">Scope</label>
60
+ <textarea id="company-scope" name="company[scope]">Food and beverage production</textarea>
61
+ </div>
62
+ </main>
63
+ </form>
64
+
65
+ <!-- Required global templates — declare once per page -->
66
+ <template data-ln-template="ln-translations-badge">
67
+ <li>
68
+ <p data-ln-translations-lang>
69
+ <span></span>
70
+ <button type="button" aria-label="Remove">
71
+ <svg class="ln-icon ln-icon--sm" aria-hidden="true"><use href="#ln-icon-x"></use></svg>
72
+ </button>
73
+ </p>
74
+ </li>
75
+ </template>
76
+
77
+ <template data-ln-template="ln-translations-menu-item">
78
+ <li><button type="button" data-ln-translations-lang></button></li>
79
+ </template>
80
+ ```
81
+
82
+ ### Variant: Server-Rendered / Pre-Hydrated Translations
83
+
84
+ When translations are already rendered server-side, mark each pre-rendered field with `data-ln-translatable-lang="{lang}"`. On init the component scans for these attributes, treats every non-default language found as already active, and renders the matching menu/badge state — no `addLanguage()` call needed.
85
+
86
+ ```html
87
+ <form data-ln-translations data-ln-translations-default="en">
88
+ <main>
89
+ <div class="form-element" data-ln-translatable="title">
90
+ <label for="doc-title">Title</label>
91
+ <input type="text" id="doc-title" name="title" value="Information Security">
92
+ <input data-ln-translatable-lang="en" name="trans[en][title]" value="Information Security" placeholder="English translation">
93
+ </div>
94
+ </main>
95
+ </form>
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 3. Declarative API Contract (Attributes & Events)
101
+
102
+ ### Attributes Table
103
+
104
+ | Attribute | Element | Type / Values | Default | Description |
105
+ |---|---|---|---|---|
106
+ | `data-ln-translations` | Container (`<form>`) | Marker | — | Initializes the translations coordinator on the container element. |
107
+ | `data-ln-translations-default` | Container | `String` | `""` | Default primary language code (e.g. `en`). Flags original translatable inputs on init. |
108
+ | `data-ln-translations-placeholder` | Container | `String` | `"{lang} translation"` | Placeholder label pattern for cloned translation inputs; `{lang}` is replaced with language display name. |
109
+ | `data-ln-translations-remove-label` | Container | `String` | `"Remove {lang}"` | Accessible label template for translation removal buttons; `{lang}` is replaced with language display name. |
110
+ | `data-ln-translations-locales` | Container | `JSON` | `{"en":"English","sq":"Shqip","sr":"Srpski"}` | JSON object mapping language codes to display labels. Auto-parsed via `attrJson`. |
111
+ | `data-ln-translations-dict` | Container | `String` | — | Dictionary key prefix mapping for translatable labels (`placeholder`, `remove-label`). |
112
+ | `data-ln-translations-menu` | Menu container | Marker | — | Explicit menu container holding available language buttons (inside or alongside `data-ln-dropdown`). |
113
+ | `data-ln-translations-active` | `<ul>` | Marker | — | Marks the mount container where active-language badges are rendered. |
114
+ | `data-ln-translations-add` | `<button>` | Trigger | — | Marks the trigger button that opens the language menu; hidden automatically once all languages are active. |
115
+ | `data-ln-translatable` | Field wrapper | `String` (field name) | — *(required)* | Marks a translatable field group; value is the field name used in generated `name` attributes. |
116
+ | `data-ln-translations-prefix` | Field wrapper | `String` | `""` | Optional name prefix for nested entities, e.g. `items[1]` produces `items[1][trans][en][title]`. |
117
+ | `data-ln-translatable-lang` | `<input>`, `<textarea>`, `<select>` | `String` (language code) | — | Marks a cloned or server-rendered translation field for a specific language. |
118
+ | `data-ln-translations-lang` | Inside templates | `String` (language code) | — *(required)* | Required anchor attribute inside both templates — populated with target language code and bindings. |
119
+
120
+ ### Programmatic JS API
121
+
122
+ The initialized instance is exposed on the container element via `dom.lnTranslations`.
123
+
124
+ | Helper | Signature | Returns | Description |
125
+ |---|---|---|---|
126
+ | `dom.lnTranslations.addLanguage` | `(lang: String, values?: Object)` | `void` | Activates `lang`, clones translatable fields (optionally seeded with `values` keyed by field name), updates menu/badges, and dispatches add lifecycle events. |
127
+ | `dom.lnTranslations.removeLanguage` | `(lang: String)` | `void` | Deactivates `lang`, removes its cloned fields, updates menu/badges, and dispatches remove lifecycle events. |
128
+ | `dom.lnTranslations.hasLanguage` | `(lang: String)` | `Boolean` | Returns whether `lang` is currently active. |
129
+ | `dom.lnTranslations.getActiveLanguages` | `()` | `Set<String>` | Returns a new `Set` copy of the active languages. |
130
+ | `dom.lnTranslations.destroy` | `()` | `void` | Removes non-default clones, cleans auto-tagged attributes, detaches request listeners, and deletes instance. |
131
+
132
+ ### Events API
133
+
134
+ | Event | Direction | Cancelable | Description | `detail` Object |
135
+ |---|---|---|---|---|
136
+ | `ln-translations:request-add` | Listens | No | Requests activation of a language programmatically. | `{ lang: String, values?: Object }` |
137
+ | `ln-translations:request-remove` | Listens | No | Requests deactivation of a language programmatically. | `{ lang: String }` |
138
+ | `ln-translations:before-add` | Emits | Yes | Fires before a language's fields are cloned. `preventDefault()` aborts activation. | `{ target: HTMLElement, lang: String, langName: String }` |
139
+ | `ln-translations:added` | Emits | No | Fires after a language's fields are cloned and menu/badges are updated. | `{ target: HTMLElement, lang: String, langName: String }` |
140
+ | `ln-translations:before-remove` | Emits | Yes | Fires before a language's cloned fields are removed. `preventDefault()` aborts removal. | `{ target: HTMLElement, lang: String }` |
141
+ | `ln-translations:removed` | Emits | No | Fires after a language's cloned fields are removed and menu/badges are updated. | `{ target: HTMLElement, lang: String }` |
142
+
143
+ ---
144
+
145
+ ## 4. CSS Styling & Behavioral Concept
146
+
147
+ `ln-translations` co-locates production SCSS: reusable mixins in `theme/config/mixins/_translations.scss` and selector bindings in `theme/components/_translations.scss`.
148
+
149
+ - **Per-language flag icons (CSS data-driven):** every `[data-ln-translatable-lang]` field, active badge, and dropdown button gets a flag icon keyed by ISO 639-1 -> ISO 3166-1 country lookup (`/assets/flags/{country}.svg`).
150
+ - **CSS Logical Properties:** spacing and positioning use `padding-inline-start`, `margin-inline-start`, and `padding-block`.
151
+ - **Cloning semantics:** `cloneNode(false)` is used for translatable inputs/textareas and `cloneNode(true)` for selects. Duplicate `id` attributes are explicitly stripped (`removeAttribute('id')`).
152
+
153
+ ---
154
+
155
+ ## 5. Accessibility (ARIA) & Common Pitfalls
156
+
157
+ - **Dynamic labels & placeholders:** cloned fields receive `placeholder` and `aria-label` matching `{langName} translation` (e.g. `English translation`), and badge remove buttons carry `aria-label="Remove {langName}"`.
158
+ - **Keyboard-native controls:** all interactive items (dropdown items, triggers, badge close buttons) are native `<button type="button">`.
159
+ - **Missing Templates Warning:** without both global `<template data-ln-template="ln-translations-badge">` and `<template data-ln-template="ln-translations-menu-item">` present on the page, `cloneTemplateScoped` returns `null` and badges/menu items cannot render.
160
+
161
+ ---
162
+
163
+ ## 6. Sequence & Lifecycle Flow
164
+
165
+ ```mermaid
166
+ sequenceDiagram
167
+ autonumber
168
+ actor User
169
+ participant Menu as Menu Item [data-ln-translations-lang]
170
+ participant Comp as ln-translations Engine
171
+ participant Wrapper as [data-ln-translatable]
172
+ participant Dropdown as Dropdown Menu
173
+ participant Badges as [data-ln-translations-active]
174
+
175
+ User->>Menu: Click language item
176
+ Menu->>Comp: addLanguage(lang)
177
+ Comp->>Comp: Emit ln-translations:before-add (cancelable)
178
+ alt Prevented
179
+ Comp->>Comp: Abort - no clones created
180
+ else Approved
181
+ Comp->>Comp: Add lang to activeLanguages Set
182
+ loop For each [data-ln-translatable] wrapper
183
+ Comp->>Wrapper: Find original input/textarea/select
184
+ Comp->>Comp: cloneNode() & removeAttribute('id')
185
+ Comp->>Comp: Set name = buildFieldName(field, lang, prefix)
186
+ Comp->>Comp: Set placeholder & aria-label
187
+ Comp->>Wrapper: Insert clone after original
188
+ end
189
+ Comp->>Dropdown: _updateDropdown() - remove lang, hide trigger if none remain
190
+ Comp->>Badges: _updateBadges() - render badge from template
191
+ Comp->>Comp: Emit ln-translations:added
192
+ end
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 7. Related Components & Coordinators
198
+
199
+ - [`ln-form`](../ln-form/README.md) — submits the generated `trans[lang][field]` fields as standard native form data.
200
+ - [`ln-dropdown`](../ln-dropdown/README.md) — provides dropdown menu positioning and dismissal behavior for language selection.
201
+ - [`ln-toggle`](../ln-toggle/README.md) — binary open/close state primitive that `ln-dropdown` coordinates.
202
+ - [`ln-validate`](../ln-validate/README.md) — validates cloned translation fields according to standard HTML constraints.
@@ -1 +1 @@
1
- (function(){"use strict";function N(){if(typeof window>"u")return!1;if(window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink)return!0;if(typeof document<"u"){if(document.documentElement&&document.documentElement.hasAttribute("data-ln-debug"))return!0;if(document.body)return document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null}return!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 i=null;for(let l=1;l<t.length;l++)if(t[l]&&t[l].nodeType===1){i=t[l];break}if(!_(i))return}e.apply(console,t)}}function S(e,t,o){const i=o||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:i}))}function T(e,t,o){const i=o||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,i);const l=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:i});return e.dispatchEvent(l),l}function C(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){C(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function ae(e){const t=e.querySelector('input[name="_method"]');return((t&&t.value!==""?t.value:e.method)||"").toUpperCase()}function se(e,t){const o=!!(t&&t.typed),i=t&&t.exclude,l={},a=e.elements,r={};if(o)for(let s=0;s<a.length;s++){const n=a[s];n.name&&n.type==="checkbox"&&!n.disabled&&(r[n.name]=(r[n.name]||0)+1)}for(let s=0;s<a.length;s++){const n=a[s];if(!(!n.name||n.disabled||n.type==="file"||n.type==="submit"||n.type==="button")&&!(i&&n.matches&&n.matches(i)))if(n.type==="checkbox")o&&r[n.name]===1?l[n.name]=n.checked:(l[n.name]||(l[n.name]=[]),n.checked&&l[n.name].push(n.value));else if(n.type==="radio")n.checked&&(l[n.name]=n.value);else if(n.type==="select-multiple"){l[n.name]=[];for(let c=0;c<n.options.length;c++)n.options[c].selected&&l[n.name].push(n.options[c].value)}else if(o&&n.type==="hidden")l[n.name]=n.value;else if(o&&(n.type==="number"||n.type==="range")){const c=Number(n.value);l[n.name]=n.value===""||isNaN(c)?null:c}else l[n.name]=n.value}return l}function ce(e){if(typeof e!="string")return!!e;const t=e.trim().toLowerCase();return t!=="false"&&t!=="0"&&t!==""&&t!=="off"&&t!=="no"}function de(e,t){const o=e.elements,i=[],l={};for(let a=0;a<o.length;a++){const r=o[a];r.name&&r.type==="checkbox"&&(l[r.name]=(l[r.name]||0)+1)}for(let a=0;a<o.length;a++){const r=o[a];if(r.type==="file"||r.type==="submit"||r.type==="button")continue;const s=r.getAttribute("data-ln-fill-as")||r.name;if(!s||!(s in t))continue;const n=t[s];if(r.type==="checkbox"){if(Array.isArray(n))r.checked=n.indexOf(r.value)!==-1;else if(l[r.name]>1){const c=String(n).split(",").map(function(u){return u.trim()});r.checked=c.indexOf(r.value)!==-1}else r.checked=ce(n);i.push(r)}else if(r.type==="radio")r.checked=r.value===String(n),i.push(r);else if(r.type==="select-multiple"){if(Array.isArray(n))for(let c=0;c<r.options.length;c++)r.options[c].selected=n.indexOf(r.options[c].value)!==-1;i.push(r)}else r.value=n,r.tagName==="SELECT"&&n!=null&&r.setAttribute("data-ln-value",n),i.push(r)}return i}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.populateForm=de,window.lnCore.serializeForm=se,window.lnCore.resolveFormMethod=ae);const $={};function ue(e,t){$[e]=t}function fe(e){return $[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=ue,window.lnCore.getDataMapper=fe);function we(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,C(function(){new MutationObserver(function(){S(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const B={};function he(e,t){if(!e||typeof t!="object")return;const o=e.toLowerCase().split("-")[0];B[o]=t}function ge(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return B[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=he,window.lnCore.getLocaleFallback=ge,window.lnCore.ensureLocaleObserver=we);const x={};function L(e,t){x[e]||(x[e]=document.querySelector('[data-ln-template="'+e+'"]'));const o=x[e];return o?o.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function M(e,t){if(!e||!t)return e;const o=e.querySelectorAll("[data-ln-field]");for(let r=0;r<o.length;r++){const s=o[r],n=s.getAttribute("data-ln-field");t[n]!=null&&(s.textContent=t[n])}const i=e.querySelectorAll("[data-ln-attr]");for(let r=0;r<i.length;r++){const s=i[r],n=s.getAttribute("data-ln-attr").split(",");for(let c=0;c<n.length;c++){const u=n[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();t[f]!=null&&s.setAttribute(d,t[f])}}const l=e.querySelectorAll("[data-ln-show]");for(let r=0;r<l.length;r++){const s=l[r],n=s.getAttribute("data-ln-show");n in t&&s.classList.toggle("hidden",!t[n])}const a=e.querySelectorAll("[data-ln-class]");for(let r=0;r<a.length;r++){const s=a[r],n=s.getAttribute("data-ln-class").split(",");for(let c=0;c<n.length;c++){const u=n[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();f in t&&s.classList.toggle(d,!!t[f])}}return e}function pe(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 o=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let i=0;i<o.length;i++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",o[i],t??null),o[i].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)M(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let o=0;o<t.length;o++)t[o].textContent=""}})));function j(e,t){if(!e||!t)return e;const o=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;o.nextNode();){const a=o.currentNode;a.textContent.indexOf("{{")!==-1&&(a.textContent=a.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(r,s){return t[s]!==void 0?t[s]:""}))}const i=function(a,r){return t[r]!==void 0?t[r]:""},l=Array.from(e.querySelectorAll("*"));e.nodeType===1&&l.push(e);for(let a=0;a<l.length;a++){const r=l[a],s=r.attributes;for(let n=0;n<s.length;n++){const c=s[n];c.value.indexOf("{{")!==-1&&r.setAttribute(c.name,c.value.replace(/\{\{\s*(\w+)\s*\}\}/g,i))}}return e}function be(e,t,o,i,l,a){const r={};for(let n=0;n<e.children.length;n++){const c=e.children[n],u=c.getAttribute("data-ln-render-key");u&&(r[u]=c)}const s=document.createDocumentFragment();for(let n=0;n<t.length;n++){const c=t[n],u=String(i(c));let d=r[u];if(d)l(d,c,n);else{const f=L(o,a);if(!f||(j(f,c),d=f.firstElementChild,!d))continue;d.setAttribute("data-ln-render-key",u),l(d,c,n)}s.appendChild(d)}e.textContent="",e.appendChild(s)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=j,window.lnCore.fill=M,window.lnCore.lnFill=pe,window.lnCore.renderList=be);function p(e,t,o){const i=e.getAttribute(t);return i===null?o:i}function U(e,t,o){const i=parseInt(e.getAttribute(t),10);return isNaN(i)?o:i}function W(e,t,o=!1){const i=e.getAttribute(t);if(i===null)return!!o;const l=i.trim().toLowerCase();return!(l==="false"||l==="0")}function P(e,t){return(e.getAttribute(t)||"").split(",").map(o=>o.trim()).filter(Boolean)}const k=new Map;function V(e,t){const o=(e?e.join("|"):"")+"::"+t;if(k.has(o))return k.get(o);const i=new Set(e||[]),l=function(a,r){const s=a.getAttribute(r);return s!==null&&i.has(s)?s:t};return k.set(o,l),l}function H(e,t,o){const i=parseFloat(e.getAttribute(t));return isNaN(i)?o:i}function K(e,t,o){const i=e.getAttribute(t);if(!i)return o;try{return JSON.parse(i)}catch{return o}}function J(e,t,o,i,l){if(!e||t===null)return!0;const a=i||"ln-component",r=e.type;if(r==="trigger"||r==="marker"||r==="string"||r==="list"||!r||t===""&&e.fallback!==void 0)return!0;const s=n=>{l?console.warn(n,l):console.warn(n)};if(r==="boolean"){const n=t.trim().toLowerCase();return n!==""&&n!=="true"&&n!=="false"&&n!=="1"&&n!=="0"?(s(`[${a}] Invalid value "${t}" for boolean attribute "${o}". Allowed: "true", "false", or presence-only.`),!1):!0}if(r==="enum"){const n=e.values||[];return n.includes(t)?!0:(s(`[${a}] Invalid value "${t}" for attribute "${o}". Allowed: ${n.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(r==="integer"){if(!/^-?\d+$/.test(t))return s(`[${a}] Invalid integer "${t}" for attribute "${o}". Fallback: ${e.fallback}.`),!1;const n=parseInt(t,10);return e.min!==void 0&&n<e.min?(s(`[${a}] Value ${n} for attribute "${o}" is less than min (${e.min}).`),!1):e.max!==void 0&&n>e.max?(s(`[${a}] Value ${n} for attribute "${o}" is greater than max (${e.max}).`),!1):!0}if(r==="float")return isNaN(Number(t))?(s(`[${a}] Invalid float "${t}" for attribute "${o}". Fallback: ${e.fallback}.`),!1):!0;if(r==="json")try{return JSON.parse(t),!0}catch(n){return s(`[${a}] Invalid JSON for attribute "${o}": ${n.message}. Fallback: ${e.fallback}.`),!1}return!0}function Q(e,t,o){for(const i in o){const[l,a,r]=o[i];Object.defineProperty(e,i,{get:function(){return l(t,a,r)},enumerable:!0,configurable:!0})}return e}function G(e){const t={};for(const o in e){const i=e[o];if(!i||!i.prop)continue;let l=i.read;if(!l&&i.type)switch(i.type){case"enum":l=V(i.values,i.fallback);break;case"integer":l=U;break;case"float":l=H;break;case"boolean":l=W;break;case"list":l=P;break;case"json":l=K;break;case"string":default:l=p;break}l||(l=p),t[i.prop]=[l,o,i.fallback]}return t}function me(e){const t={};for(const o in e){const i=e[o];i&&i.effect&&(t[o]=i.effect)}return Object.keys(t).length?t:null}function ye(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const o in e.effects)t.add(o);if(e.onAttrChange&&e.declared)for(const o of e.declared)t.add(o);return t}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.defineAttrs=Q,window.lnCore.attrSpec=G,window.lnCore.attrStr=p,window.lnCore.attrInt=U,window.lnCore.attrBool=W,window.lnCore.attrList=P,window.lnCore.attrEnum=V,window.lnCore.attrFloat=H,window.lnCore.attrJson=K);function A(e,t){if(!e[t.attribute]){window.lnCore._persistSink&&e.hasAttribute&&e.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(e,t.selector);try{e[t.attribute]=new t.ComponentFn(e)}catch(o){console.error("["+t.attribute+"] init failed",e,o)}}}function z(e,t,o,i){if(e.nodeType!==1)return;const a=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",r={selector:t,attribute:o,ComponentFn:i};if(e.matches&&e.matches(a)&&A(e,r),e.querySelectorAll){const s=e.querySelectorAll(a);for(let n=0;n<s.length;n++)A(s[n],r)}}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 Ae(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 X(){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 ve(e){const t=X(),o=e.observed||[];for(let i=0;i<o.length;i++){const l=o[i];t.byAttr.has(l)||t.byAttr.set(l,[]),t.byAttr.get(l).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const i in e.attributes){t.byDeclaredAttr.has(i)||t.byDeclaredAttr.set(i,[]);const l=t.byDeclaredAttr.get(i);l.some(a=>a.componentTag===e.componentTag)||l.push({spec:e.attributes[i],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const i=ye(e);if(i===null)t.reactiveWildcard.push(e);else for(const l of i)t.byReactive.has(l)||t.byReactive.set(l,[]),t.byReactive.get(l).push(e)}e.persist&&t.persist.push(e)}function Y(e,t,o,i){for(let l=0;l<e.length;l++){const a=e[l];if(!t[a.attribute])continue;const r=a.effects&&a.effects[o];r?r(t,o,i):a.onAttrChange&&(!a.declared||a.declared.has(o))&&a.onAttrChange(t,o,i)}}function _e(e){const t=e.attributeName,o=t.indexOf("data-ln-")===0,i=X(),l=i.byAttr.get(t),a=N()&&i.byDeclaredAttr&&i.byDeclaredAttr.has(t);if(!o&&!l&&!a)return;const r=e.target;if(e.oldValue!==r.getAttribute(t)){if(a&&_(r)){const s=i.byDeclaredAttr.get(t),n=r.getAttribute(t);for(let c=0;c<s.length;c++)J(s[c].spec,n,t,s[c].componentTag,r)}if(window.lnCore._debugSink&&(o||l)&&window.lnCore._debugSink("attr",t,r,{oldValue:e.oldValue,newValue:r.getAttribute(t)}),o){const s=i.byReactive.get(t);s&&Y(s,r,t,e.oldValue),i.reactiveWildcard.length&&Y(i.reactiveWildcard,r,t,e.oldValue)}if(l)for(let s=0;s<l.length;s++){const n=l[s];if(n.handler){n.handler(r,t,e.oldValue);continue}n.onAttributeChange&&r[n.attribute]?n.onAttributeChange(r,t):(z(r,n.selector,n.attribute,n.ComponentFn),n.onInit&&n.onInit(r))}}}function Se(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,C(function(){new MutationObserver(function(t){for(let o=0;o<t.length;o++)try{_e(t[o])}catch(i){console.error("[ln-core] mutation handler failed",t[o].target,i)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function E(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function q(){return window.lnCore=window.lnCore||{},window.lnCore._subtreeRegistry=window.lnCore._subtreeRegistry||[]}function Z(e,t){if(!document.contains(e))if(t.attribute){const o=e[t.attribute];if(o&&typeof o.destroy=="function")try{o.destroy()}catch(i){console.error("["+t.attribute+"] destroy failed",e,i)}delete e[t.attribute]}else t.onDestroy&&t.onDestroy(e)}function ee(e){const t=E();if(!t.length)return;const o=e.target;if(o){const l=o.nodeType===1?o:o.parentElement;if(l&&(l.isContentEditable||l.closest&&l.closest('[contenteditable]:not([contenteditable="false"])')))return}const i=q();if(e.target&&i.length)for(let l=0;l<i.length;l++){const a=i[l],r=a.query,s=e.target.nodeType===1?e.target.matches&&e.target.matches(r)?e.target:e.target.closest?e.target.closest(r):null:e.target.parentElement&&e.target.parentElement.closest?e.target.parentElement.closest(r):null;s&&a.onSubtreeChange(s,e)}for(let l=0;l<e.addedNodes.length;l++){const a=e.addedNodes[l];if(a.nodeType!==1)continue;const r=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const n=t[s],c=n.query;if(c&&(a.matches&&a.matches(c)&&(n.ComponentFn&&A(a,n),n.onInit&&n.onInit(a)),r&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)n.ComponentFn&&A(u[d],n),n.onInit&&n.onInit(u[d])}}}for(let l=0;l<e.removedNodes.length;l++){const a=e.removedNodes[l];if(a.nodeType!==1||document.contains(a))continue;const r=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const n=t[s],c=n.query;if(c&&(a.matches&&a.matches(c)&&Z(a,n),r&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)Z(u[d],n)}}}}function te(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,C(function(){const e=new MutationObserver(function(t){for(let o=0;o<t.length;o++){const i=t[o];if(i.type==="childList")try{ee(i)}catch(l){console.error("[ln-core] lifecycle handler failed",i.target,l)}}});window.lnCore._lifecycleObserver=e,e.observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function xe(e){if(typeof window>"u")return e();window.lnCore=window.lnCore||{};const t=window.lnCore._lifecycleObserver;if(!t)return e();const o=t.takeRecords();for(let i=0;i<o.length;i++){const l=o[i];if(l.type==="childList")try{ee(l)}catch(a){console.error("[ln-core] lifecycle handler failed",l.target,a)}}t.disconnect();try{return e()}finally{t.observe(document.body,{childList:!0,subtree:!0})}}function Le(e){E().push(e),e.onSubtreeChange&&e.query&&q().push(e),te()}function ne(e,t,o,i,l={}){const a=l.extraAttributes||[],r=l.onAttributeChange||null,s=l.onSubtreeChange||null,n=l.onInit||null,c=l.onAttrChange||null,u=l.effects||null,d=l.attributes||null,f=d?me(d):u,h=d?new Set(Object.keys(d)):null,m=l.persist||null;function w(D){const g=D||document.body;if(z(g,e,t,o),d&&N())for(const y in d){const He=d[y],R=Array.from(g.querySelectorAll("["+y+"]"));g.matches&&g.matches("["+y+"]")&&R.push(g);for(let I=0;I<R.length;I++){const F=R[I];_(F)&&J(He,F.getAttribute(y),y,i,F)}}n&&n(g)}const b=[];if(e.indexOf("[")!==-1){const D=/\[([\w-]+)/g;let g;for(;(g=D.exec(e))!==null;)b.push(g[1])}else b.push(e);ve({selector:e,attribute:t,componentTag:i,attributes:d,ComponentFn:o,onInit:n,observed:b.concat(a),onAttributeChange:r,onAttrChange:c,effects:f,declared:h,persist:m}),Se();const v=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1,oe=l.subtreeQuery||(v?e:"["+e+"]"),ie={selector:e,attribute:t,ComponentFn:o,onInit:n,onSubtreeChange:s,query:oe};E().push(ie),s&&oe&&q().push(ie),te(),window[t]=w,typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerComponent=ne,window.lnCore.observeLifecycle=Le,window.lnCore.withoutLifecycle=xe);function le(){Ce()>0?Ae(function(){w(document.body)}):w(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",le):le(),w}function re(e){return(e||"").replace(/^#/,"")}function O(e){const t=e===void 0?location.hash:e,o={},i=re(t);if(!i)return o;const l=i.split("&");for(let a=0;a<l.length;a++){const r=l[a];if(!r)continue;const s=r.indexOf(":"),n=s>-1?r.slice(0,s):r,c=s>-1?r.slice(s+1):"";if(n)try{o[n]=decodeURIComponent(c)}catch{o[n]=c}}return o}function ke(e){if(!e)return null;const t=O();return e in t?t[e]:null}function Ee(e,t){if(!e)return;const o=O();t==null?delete o[e]:o[e]=String(t);const l=Object.keys(o).map(function(a){const r=o[a];return r===""?a:a+":"+encodeURIComponent(r)}).join("&");re(location.hash)!==l&&(location.hash=l)}function qe(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Oe(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const o=e.getAttribute("data-ln-hash");if(o&&o.trim()!=="")return o.trim();const i=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return i?t?i+"-"+t:i:t||null}function De(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Re(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 Ie(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Fe(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const o=e.slice(0,t),i=e.slice(t+1),l=i?i.split(",").map(function(a){try{return decodeURIComponent(a)}catch{return a}}).filter(Boolean):[];return{key:o,values:l}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=O,window.lnCore.hashGet=ke,window.lnCore.hashSet=Ee,window.lnCore.hashLinkClick=qe,window.lnCore.resolveHashNamespace=Oe,window.lnCore.hashSortEncode=De,window.lnCore.hashSortDecode=Re,window.lnCore.hashFilterEncode=Ie,window.lnCore.hashFilterDecode=Fe);function Ne(e){return(e||"").replace(/^\?/,"")}function Te(e){const t=e===void 0?typeof window<"u"?window.location.search:"":e,o={},i=Ne(t);if(!i)return o;const l=new URLSearchParams(i);for(const[a,r]of l.entries())o[a]=r;return o}function $e(e){if(!e||typeof window>"u")return null;const t=new URLSearchParams(window.location.search);return t.has(e)?t.get(e):null}function Be(e,t){if(!e||typeof window>"u")return;const o=new URL(window.location.href);if(t==null||t===""?o.searchParams.delete(e):o.searchParams.set(e,String(t)),o.search===window.location.search)return;const i=o.pathname+o.search+o.hash;window.history.replaceState(window.history.state,"",i)}function Me(e,t){if(!e||!e.hasAttribute("data-ln-query"))return null;const o=e.getAttribute("data-ln-query");if(o&&o.trim()!=="")return o.trim();const i=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return i?t?i+"_"+t:i:t||null}function je(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ue(e,t){if(e&&typeof e=="string"){if(e.endsWith(".asc"))return{fieldOrColumn:e.slice(0,-4),direction:"asc"};if(e.endsWith(".desc"))return{fieldOrColumn:e.slice(0,-5),direction:"desc"}}if(t&&typeof t=="object"){const o=t.sort_field||t.sort_by;if(o){const i=t.sort_dir&&String(t.sort_dir).toLowerCase()==="desc"?"desc":"asc";return{fieldOrColumn:o,direction:i}}}return null}function We(e){return!Array.isArray(e)||e.length===0?null:e.map(encodeURIComponent).join(",")}function Pe(e){return!e||typeof e!="string"?[]:e.split(",").map(function(t){try{return decodeURIComponent(t.trim())}catch{return t.trim()}}).filter(Boolean)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.queryParse=Te,window.lnCore.queryGet=$e,window.lnCore.querySet=Be,window.lnCore.resolveQueryParam=Me,window.lnCore.querySortEncode=je,window.lnCore.querySortDecode=Ue,window.lnCore.queryFilterEncode=We,window.lnCore.queryFilterDecode=Pe);function Ve(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.uuid=Ve),(function(){const e="data-ln-translations",t="lnTranslations";if(window[t]!==void 0)return;const o={"data-ln-translations":{type:"marker",description:"Mounts multi-language translation manager on form container"},"data-ln-translations-default":{prop:"defaultLang",read:p,type:"string",fallback:"",description:"Default primary language code (e.g. en)"},"data-ln-translations-placeholder":{prop:"placeholderLabel",read:p,type:"string",fallback:"{lang} translation",description:"Placeholder label pattern for cloned translation inputs"},"data-ln-translations-remove-label":{prop:"removeLabel",read:p,type:"string",fallback:"Remove {lang}",description:"Accessible label template for translation removal buttons"},"data-ln-translations-locales":{prop:"_localesRaw",read:p,type:"json",fallback:"",description:"JSON dictionary of supported locale codes and display labels"},"data-ln-translations-active":{type:"marker",description:"Container holding active language badge tags"},"data-ln-translations-add":{type:"string",description:"Trigger button action to add specified language translation fields"},"data-ln-translations-lang":{type:"string",description:"Language code associated with active language badge"},"data-ln-translations-prefix":{type:"string",description:"Prefix format pattern for cloned translated field names"},"data-ln-translatable":{type:"marker",description:"Marks form control as translatable into multiple languages"},"data-ln-translatable-lang":{type:"string",description:"Language code assigned to specific translatable input instance"}},i=G(o),l={en:"English",sq:"Shqip",sr:"Srpski"};function a(r){if(this.dom=r,Q(this,r,i),this.activeLanguages=new Set,this.badgesEl=r.querySelector("[data-ln-translations-active]"),this.menuEl=r.querySelector("[data-ln-dropdown] > [data-ln-toggle]"),this.locales=l,this._localesRaw)try{this.locales=JSON.parse(this._localesRaw)}catch{console.warn("[ln-translations] Invalid JSON in data-ln-translations-locales")}this._applyDefaultLang(),this._updateDropdown();const s=this;return this._onRequestAdd=function(n){n.detail&&n.detail.lang&&s.addLanguage(n.detail.lang)},this._onRequestRemove=function(n){n.detail&&n.detail.lang&&s.removeLanguage(n.detail.lang)},r.addEventListener("ln-translations:request-add",this._onRequestAdd),r.addEventListener("ln-translations:request-remove",this._onRequestRemove),this._detectExisting(),this}a.prototype._applyDefaultLang=function(){if(!this.defaultLang)return;const r=this.dom.querySelectorAll("[data-ln-translatable]");for(const s of r){const n=s.querySelectorAll("input:not([data-ln-translatable-lang]), textarea:not([data-ln-translatable-lang]), select:not([data-ln-translatable-lang])");for(const c of n)c.setAttribute("data-ln-translatable-lang",this.defaultLang)}},a.prototype._detectExisting=function(){const r=this.dom.querySelectorAll("[data-ln-translatable-lang]");for(const s of r){const n=s.getAttribute("data-ln-translatable-lang");n&&n!==this.defaultLang&&this.activeLanguages.add(n)}this.activeLanguages.size>0&&(this._updateBadges(),this._updateDropdown())},a.prototype._updateDropdown=function(){if(!this.menuEl)return;this.menuEl.textContent="";const r=this;let s=0;for(const c in this.locales){if(!this.locales.hasOwnProperty(c)||this.activeLanguages.has(c))continue;s++;const u=L("ln-translations-menu-item","ln-translations");if(!u)return;const d=u.querySelector("[data-ln-translations-lang]");d.setAttribute("data-ln-translations-lang",c),d.textContent=this.locales[c],d.addEventListener("click",function(f){f.ctrlKey||f.metaKey||f.button===1||(f.preventDefault(),f.stopPropagation(),r.menuEl.getAttribute("data-ln-toggle")==="open"&&r.menuEl.setAttribute("data-ln-toggle","close"),r.addLanguage(c))}),this.menuEl.appendChild(u)}const n=this.dom.querySelector("[data-ln-translations-add]");n&&(n.hidden=s===0)},a.prototype._updateBadges=function(){if(!this.badgesEl)return;this.badgesEl.textContent="";const r=this;this.activeLanguages.forEach(function(s){const n=L("ln-translations-badge","ln-translations");if(!n)return;const c=n.querySelector("[data-ln-translations-lang]");c.setAttribute("data-ln-translations-lang",s);const u=c.querySelector("span");u.textContent=r.locales[s]||s.toUpperCase();const d=c.querySelector("button"),f=r.locales[s]||s.toUpperCase();d.setAttribute("aria-label",r.removeLabel.replace("{lang}",f)),d.addEventListener("click",function(h){h.ctrlKey||h.metaKey||h.button===1||(h.preventDefault(),h.stopPropagation(),r.removeLanguage(s))}),r.badgesEl.appendChild(n)})},a.prototype.addLanguage=function(r,s){if(this.activeLanguages.has(r))return;const n=this.locales[r]||r;if(T(this.dom,"ln-translations:before-add",{target:this.dom,lang:r,langName:n}).defaultPrevented)return;this.activeLanguages.add(r),s=s||{};const u=this.dom.querySelectorAll("[data-ln-translatable]");for(const d of u){const f=d.getAttribute("data-ln-translatable"),h=d.getAttribute("data-ln-translations-prefix")||"",m=d.querySelector(this.defaultLang?'[data-ln-translatable-lang="'+this.defaultLang+'"]':"input:not([data-ln-translatable-lang]), textarea:not([data-ln-translatable-lang]), select:not([data-ln-translatable-lang])");if(!m)continue;const w=m.cloneNode(m.tagName==="SELECT");h?w.name=h+"[trans]["+r+"]["+f+"]":w.name="trans["+r+"]["+f+"]",w.value=s[f]!==void 0?s[f]:"",w.removeAttribute("id"),"placeholder"in w&&(w.placeholder=this.placeholderLabel.replace("{lang}",n)),w.setAttribute("data-ln-translatable-lang",r);const b=d.querySelectorAll('[data-ln-translatable-lang]:not([data-ln-translatable-lang="'+this.defaultLang+'"])'),v=b.length>0?b[b.length-1]:m;v.parentNode.insertBefore(w,v.nextSibling)}this._updateDropdown(),this._updateBadges(),S(this.dom,"ln-translations:added",{target:this.dom,lang:r,langName:n})},a.prototype.removeLanguage=function(r){if(!this.activeLanguages.has(r)||T(this.dom,"ln-translations:before-remove",{target:this.dom,lang:r}).defaultPrevented)return;const n=this.dom.querySelectorAll('[data-ln-translatable-lang="'+r+'"]');for(const c of n)c.parentNode.removeChild(c);this.activeLanguages.delete(r),this._updateDropdown(),this._updateBadges(),S(this.dom,"ln-translations:removed",{target:this.dom,lang:r})},a.prototype.getActiveLanguages=function(){return new Set(this.activeLanguages)},a.prototype.hasLanguage=function(r){return this.activeLanguages.has(r)},a.prototype.destroy=function(){if(!this.dom[t])return;const r=this.defaultLang,s=this.dom.querySelectorAll("[data-ln-translatable-lang]");for(const n of s)n.getAttribute("data-ln-translatable-lang")!==r&&n.parentNode.removeChild(n);this.dom.removeEventListener("ln-translations:request-add",this._onRequestAdd),this.dom.removeEventListener("ln-translations:request-remove",this._onRequestRemove),delete this.dom[t]},ne(e,t,a,"ln-translations",{attributes:o})})()})();
1
+ (function(){"use strict";function B(){if(typeof window>"u")return!1;if(window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink)return!0;if(typeof document<"u"){if(document.documentElement&&document.documentElement.hasAttribute("data-ln-debug"))return!0;if(document.body)return document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null}return!1}function S(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 l=null;for(let i=1;i<t.length;i++)if(t[i]&&t[i].nodeType===1){l=t[i];break}if(!S(l))return}e.apply(console,t)}}function x(e,t,n){const l=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,l),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:l}))}function $(e,t,n){const l=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,l);const i=new CustomEvent(t,{bubbles:!0,cancelable:!0,detail:l});return e.dispatchEvent(i),i}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()}function M(e){return!!(!e||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||typeof e.button=="number"&&e.button!==0)}function ue(e){const t=e.querySelector('input[name="_method"]');return((t&&t.value!==""?t.value:e.method)||"").toUpperCase()}function de(e,t){const n=!!(t&&t.typed),l=t&&t.exclude,i={},a=e.elements,o={};if(n)for(let s=0;s<a.length;s++){const r=a[s];r.name&&r.type==="checkbox"&&!r.disabled&&(o[r.name]=(o[r.name]||0)+1)}for(let s=0;s<a.length;s++){const r=a[s];if(!(!r.name||r.disabled||r.type==="file"||r.type==="submit"||r.type==="button")&&!(l&&r.matches&&r.matches(l)))if(r.type==="checkbox")n&&o[r.name]===1?i[r.name]=r.checked:(i[r.name]||(i[r.name]=[]),r.checked&&i[r.name].push(r.value));else if(r.type==="radio")r.checked&&(i[r.name]=r.value);else if(r.type==="select-multiple"){i[r.name]=[];for(let c=0;c<r.options.length;c++)r.options[c].selected&&i[r.name].push(r.options[c].value)}else if(n&&r.type==="hidden")i[r.name]=r.value;else if(n&&(r.type==="number"||r.type==="range")){const c=Number(r.value);i[r.name]=r.value===""||isNaN(c)?null:c}else i[r.name]=r.value}return i}function fe(e){if(typeof e!="string")return!!e;const t=e.trim().toLowerCase();return t!=="false"&&t!=="0"&&t!==""&&t!=="off"&&t!=="no"}function ge(e,t){const n=e.elements,l=[],i={};for(let a=0;a<n.length;a++){const o=n[a];o.name&&o.type==="checkbox"&&(i[o.name]=(i[o.name]||0)+1)}for(let a=0;a<n.length;a++){const o=n[a];if(o.type==="file"||o.type==="submit"||o.type==="button")continue;const s=o.getAttribute("data-ln-fill-as")||o.name;if(!s||!(s in t))continue;const r=t[s];if(o.type==="checkbox"){if(Array.isArray(r))o.checked=r.indexOf(o.value)!==-1;else if(i[o.name]>1){const c=String(r).split(",").map(function(u){return u.trim()});o.checked=c.indexOf(o.value)!==-1}else o.checked=fe(r);l.push(o)}else if(o.type==="radio")o.checked=o.value===String(r),l.push(o);else if(o.type==="select-multiple"){if(Array.isArray(r))for(let c=0;c<o.options.length;c++)o.options[c].selected=r.indexOf(o.options[c].value)!==-1;l.push(o)}else o.value=r,o.tagName==="SELECT"&&r!=null&&o.setAttribute("data-ln-value",r),l.push(o)}return l}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.populateForm=ge,window.lnCore.serializeForm=de,window.lnCore.resolveFormMethod=ue);const j={};function he(e,t){j[e]=t}function we(e){return j[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=he,window.lnCore.getDataMapper=we);function pe(e){const t=e?e.closest("[lang]"):null,n=(t?t.getAttribute("lang")||t.lang:null)||(typeof document<"u"&&document.documentElement?document.documentElement.getAttribute("lang")||document.documentElement.lang:null)||(typeof navigator<"u"?navigator.language:null);return n?n.trim():"en-US"}function be(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){x(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const U={};function me(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];U[n]=t}function ye(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return U[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=me,window.lnCore.getLocaleFallback=ye,window.lnCore.ensureLocaleObserver=be);const L={};function v(e,t){L[e]||(L[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=L[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function W(e,t,n){if(e){const l=e.querySelector('[data-ln-template="'+t+'"]');if(l)return l.content.cloneNode(!0)}return v(t,n)}function P(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let o=0;o<n.length;o++){const s=n[o],r=s.getAttribute("data-ln-field");t[r]!=null&&(s.textContent=t[r])}const l=e.querySelectorAll("[data-ln-attr]");for(let o=0;o<l.length;o++){const s=l[o],r=s.getAttribute("data-ln-attr").split(",");for(let c=0;c<r.length;c++){const u=r[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();t[f]!=null&&s.setAttribute(d,t[f])}}const i=e.querySelectorAll("[data-ln-show]");for(let o=0;o<i.length;o++){const s=i[o],r=s.getAttribute("data-ln-show");r in t&&s.classList.toggle("hidden",!t[r])}const a=e.querySelectorAll("[data-ln-class]");for(let o=0;o<a.length;o++){const s=a[o],r=s.getAttribute("data-ln-class").split(",");for(let c=0;c<r.length;c++){const u=r[c].trim().split(":");if(u.length!==2)continue;const d=u[0].trim(),f=u[1].trim();f in t&&s.classList.toggle(d,!!t[f])}}return e}function Ce(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 l=0;l<n.length;l++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[l],t??null),n[l].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)P(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 V(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const a=n.currentNode;a.textContent.indexOf("{{")!==-1&&(a.textContent=a.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(o,s){return t[s]!==void 0?t[s]:""}))}const l=function(a,o){return t[o]!==void 0?t[o]:""},i=Array.from(e.querySelectorAll("*"));e.nodeType===1&&i.push(e);for(let a=0;a<i.length;a++){const o=i[a],s=o.attributes;for(let r=0;r<s.length;r++){const c=s[r];c.value.indexOf("{{")!==-1&&o.setAttribute(c.name,c.value.replace(/\{\{\s*(\w+)\s*\}\}/g,l))}}return e}function Ae(e,t,n,l,i,a){const o={};for(let r=0;r<e.children.length;r++){const c=e.children[r],u=c.getAttribute("data-ln-render-key");u&&(o[u]=c)}const s=document.createDocumentFragment();for(let r=0;r<t.length;r++){const c=t[r],u=String(l(c));let d=o[u];if(d)i(d,c,r);else{const f=v(n,a);if(!f||(V(f,c),d=f.firstElementChild,!d))continue;d.setAttribute("data-ln-render-key",u),i(d,c,r)}s.appendChild(d)}e.textContent="",e.appendChild(s)}function ve(e,t){const n={},l=e.querySelectorAll("["+t+"]");for(let i=0;i<l.length;i++)n[l[i].getAttribute(t)]=l[i].textContent,l[i].remove();return n}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=V,window.lnCore.fill=P,window.lnCore.lnFill=Ce,window.lnCore.renderList=Ae);function p(e,t,n){const l=e.getAttribute(t);return l===null?n:l}function H(e,t,n){const l=parseInt(e.getAttribute(t),10);return isNaN(l)?n:l}function K(e,t,n=!1){const l=e.getAttribute(t);if(l===null)return!!n;const i=l.trim().toLowerCase();return!(i==="false"||i==="0")}function Q(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const k=new Map;function J(e,t){const n=(e?e.join("|"):"")+"::"+t;if(k.has(n))return k.get(n);const l=new Set(e||[]),i=function(a,o){const s=a.getAttribute(o);return s!==null&&l.has(s)?s:t};return k.set(n,i),i}function z(e,t,n){const l=parseFloat(e.getAttribute(t));return isNaN(l)?n:l}function E(e,t,n){const l=e.getAttribute(t);if(!l)return n;try{return JSON.parse(l)}catch{return n}}function G(e,t,n,l,i){if(!e||t===null)return!0;const a=l||"ln-component",o=e.type;if(o==="trigger"||o==="marker"||o==="string"||o==="list"||!o||t===""&&e.fallback!==void 0)return!0;const s=r=>{i?console.warn(r,i):console.warn(r)};if(o==="boolean"){const r=t.trim().toLowerCase();return r!==""&&r!=="true"&&r!=="false"&&r!=="1"&&r!=="0"?(s(`[${a}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(o==="enum"){const r=e.values||[];return r.includes(t)?!0:(s(`[${a}] Invalid value "${t}" for attribute "${n}". Allowed: ${r.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(o==="integer"){if(!/^-?\d+$/.test(t))return s(`[${a}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const r=parseInt(t,10);return e.min!==void 0&&r<e.min?(s(`[${a}] Value ${r} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&r>e.max?(s(`[${a}] Value ${r} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(o==="float")return isNaN(Number(t))?(s(`[${a}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(o==="json")try{return JSON.parse(t),!0}catch(r){return s(`[${a}] Invalid JSON for attribute "${n}": ${r.message}. Fallback: ${e.fallback}.`),!1}return!0}function X(e,t,n){for(const l in n){const[i,a,o]=n[l];Object.defineProperty(e,l,{get:function(){return i(t,a,o)},enumerable:!0,configurable:!0})}return e}function Y(e){const t={};for(const n in e){const l=e[n];if(!l||!l.prop)continue;let i=l.read;if(!i&&l.type)switch(l.type){case"enum":i=J(l.values,l.fallback);break;case"integer":i=H;break;case"float":i=z;break;case"boolean":i=K;break;case"list":i=Q;break;case"json":i=E;break;case"string":default:i=p;break}i||(i=p),t[l.prop]=[i,n,l.fallback]}return t}function _e(e){const t={};for(const n in e){const l=e[n];l&&l.effect&&(t[n]=l.effect)}return Object.keys(t).length?t:null}function Se(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}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.defineAttrs=X,window.lnCore.attrSpec=Y,window.lnCore.attrStr=p,window.lnCore.attrInt=H,window.lnCore.attrBool=K,window.lnCore.attrList=Q,window.lnCore.attrEnum=J,window.lnCore.attrFloat=z,window.lnCore.attrJson=E);function _(e,t){if(!e[t.attribute]){window.lnCore._persistSink&&e.hasAttribute&&e.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(e,t.selector);try{e[t.attribute]=new t.ComponentFn(e)}catch(n){console.error("["+t.attribute+"] init failed",e,n)}}}function Z(e,t,n,l){if(e.nodeType!==1)return;const a=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",o={selector:t,attribute:n,ComponentFn:l};if(e.matches&&e.matches(a)&&_(e,o),e.querySelectorAll){const s=e.querySelectorAll(a);for(let r=0;r<s.length;r++)_(s[r],o)}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function xe(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function Le(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 ee(){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 ke(e){const t=ee(),n=e.observed||[];for(let l=0;l<n.length;l++){const i=n[l];t.byAttr.has(i)||t.byAttr.set(i,[]),t.byAttr.get(i).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const l in e.attributes){t.byDeclaredAttr.has(l)||t.byDeclaredAttr.set(l,[]);const i=t.byDeclaredAttr.get(l);i.some(a=>a.componentTag===e.componentTag)||i.push({spec:e.attributes[l],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const l=Se(e);if(l===null)t.reactiveWildcard.push(e);else for(const i of l)t.byReactive.has(i)||t.byReactive.set(i,[]),t.byReactive.get(i).push(e)}e.persist&&t.persist.push(e)}function te(e,t,n,l){for(let i=0;i<e.length;i++){const a=e[i];if(!t[a.attribute])continue;const o=a.effects&&a.effects[n];o?o(t,n,l):a.onAttrChange&&(!a.declared||a.declared.has(n))&&a.onAttrChange(t,n,l)}}function Ee(e){const t=e.attributeName,n=t.indexOf("data-ln-")===0,l=ee(),i=l.byAttr.get(t),a=B()&&l.byDeclaredAttr&&l.byDeclaredAttr.has(t);if(!n&&!i&&!a)return;const o=e.target;if(e.oldValue!==o.getAttribute(t)){if(a&&S(o)){const s=l.byDeclaredAttr.get(t),r=o.getAttribute(t);for(let c=0;c<s.length;c++)G(s[c].spec,r,t,s[c].componentTag,o)}if(window.lnCore._debugSink&&(n||i)&&window.lnCore._debugSink("attr",t,o,{oldValue:e.oldValue,newValue:o.getAttribute(t)}),n){const s=l.byReactive.get(t);s&&te(s,o,t,e.oldValue),l.reactiveWildcard.length&&te(l.reactiveWildcard,o,t,e.oldValue)}if(i)for(let s=0;s<i.length;s++){const r=i[s];if(r.handler){r.handler(o,t,e.oldValue);continue}r.onAttributeChange&&o[r.attribute]?r.onAttributeChange(o,t):(Z(o,r.selector,r.attribute,r.ComponentFn),r.onInit&&r.onInit(o))}}}function qe(){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{Ee(t[n])}catch(l){console.error("[ln-core] mutation handler failed",t[n].target,l)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function q(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function D(){return window.lnCore=window.lnCore||{},window.lnCore._subtreeRegistry=window.lnCore._subtreeRegistry||[]}function ne(e,t){if(!document.contains(e))if(t.attribute){const n=e[t.attribute];if(n&&typeof n.destroy=="function")try{n.destroy()}catch(l){console.error("["+t.attribute+"] destroy failed",e,l)}delete e[t.attribute]}else t.onDestroy&&t.onDestroy(e)}function re(e){const t=q();if(!t.length)return;const n=e.target;if(n){const i=n.nodeType===1?n:n.parentElement;if(i&&(i.isContentEditable||i.closest&&i.closest('[contenteditable]:not([contenteditable="false"])')))return}const l=D();if(e.target&&l.length)for(let i=0;i<l.length;i++){const a=l[i],o=a.query,s=e.target.nodeType===1?e.target.matches&&e.target.matches(o)?e.target:e.target.closest?e.target.closest(o):null:e.target.parentElement&&e.target.parentElement.closest?e.target.parentElement.closest(o):null;s&&a.onSubtreeChange(s,e)}for(let i=0;i<e.addedNodes.length;i++){const a=e.addedNodes[i];if(a.nodeType!==1)continue;const o=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const r=t[s],c=r.query;if(c&&(a.matches&&a.matches(c)&&(r.ComponentFn&&_(a,r),r.onInit&&r.onInit(a)),o&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)r.ComponentFn&&_(u[d],r),r.onInit&&r.onInit(u[d])}}}for(let i=0;i<e.removedNodes.length;i++){const a=e.removedNodes[i];if(a.nodeType!==1||document.contains(a))continue;const o=!!(a.firstElementChild||a.children&&a.children.length);for(let s=0;s<t.length;s++){const r=t[s],c=r.query;if(c&&(a.matches&&a.matches(c)&&ne(a,r),o&&a.querySelectorAll)){const u=a.querySelectorAll(c);for(let d=0;d<u.length;d++)ne(u[d],r)}}}}function oe(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){const e=new MutationObserver(function(t){for(let n=0;n<t.length;n++){const l=t[n];if(l.type==="childList")try{re(l)}catch(i){console.error("[ln-core] lifecycle handler failed",l.target,i)}}});window.lnCore._lifecycleObserver=e,e.observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function De(e){if(typeof window>"u")return e();window.lnCore=window.lnCore||{};const t=window.lnCore._lifecycleObserver;if(!t)return e();const n=t.takeRecords();for(let l=0;l<n.length;l++){const i=n[l];if(i.type==="childList")try{re(i)}catch(a){console.error("[ln-core] lifecycle handler failed",i.target,a)}}t.disconnect();try{return e()}finally{t.observe(document.body,{childList:!0,subtree:!0})}}function Oe(e){q().push(e),e.onSubtreeChange&&e.query&&D().push(e),oe()}function ie(e,t,n,l,i={}){const a=i.extraAttributes||[],o=i.onAttributeChange||null,s=i.onSubtreeChange||null,r=i.onInit||null,c=i.onAttrChange||null,u=i.effects||null,d=i.attributes||null,f=d?_e(d):u,b=d?new Set(Object.keys(d)):null,R=i.persist||null;function h(N){const w=N||document.body;if(Z(w,e,t,n),d&&B())for(const C in d){const tt=d[C],I=Array.from(w.querySelectorAll("["+C+"]"));w.matches&&w.matches("["+C+"]")&&I.push(w);for(let F=0;F<I.length;F++){const T=I[F];S(T)&&G(tt,T.getAttribute(C),C,l,T)}}r&&r(w)}const g=[];if(e.indexOf("[")!==-1){const N=/\[([\w-]+)/g;let w;for(;(w=N.exec(e))!==null;)g.push(w[1])}else g.push(e);ke({selector:e,attribute:t,componentTag:l,attributes:d,ComponentFn:n,onInit:r,observed:g.concat(a),onAttributeChange:o,onAttrChange:c,effects:f,declared:b,persist:R}),qe();const m=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1,y=i.subtreeQuery||(m?e:"["+e+"]"),se={selector:e,attribute:t,ComponentFn:n,onInit:r,onSubtreeChange:s,query:y};q().push(se),s&&y&&D().push(se),oe(),window[t]=h,typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerComponent=ie,window.lnCore.observeLifecycle=Oe,window.lnCore.withoutLifecycle=De);function ce(){xe()>0?Le(function(){h(document.body)}):h(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",ce):ce(),h}function le(e){return(e||"").replace(/^#/,"")}function O(e){const t=e===void 0?location.hash:e,n={},l=le(t);if(!l)return n;const i=l.split("&");for(let a=0;a<i.length;a++){const o=i[a];if(!o)continue;const s=o.indexOf(":"),r=s>-1?o.slice(0,s):o,c=s>-1?o.slice(s+1):"";if(r)try{n[r]=decodeURIComponent(c)}catch{n[r]=c}}return n}function Re(e){if(!e)return null;const t=O();return e in t?t[e]:null}function Ne(e,t){if(!e)return;const n=O();t==null?delete n[e]:n[e]=String(t);const i=Object.keys(n).map(function(a){const o=n[a];return o===""?a:a+":"+encodeURIComponent(o)}).join("&");le(location.hash)!==i&&(location.hash=i)}function Ie(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Fe(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 l=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return l?t?l+"-"+t:l:t||null}function Te(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Be(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 $e(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Me(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),l=e.slice(t+1),i=l?l.split(",").map(function(a){try{return decodeURIComponent(a)}catch{return a}}).filter(Boolean):[];return{key:n,values:i}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=O,window.lnCore.hashGet=Re,window.lnCore.hashSet=Ne,window.lnCore.hashLinkClick=Ie,window.lnCore.resolveHashNamespace=Fe,window.lnCore.hashSortEncode=Te,window.lnCore.hashSortDecode=Be,window.lnCore.hashFilterEncode=$e,window.lnCore.hashFilterDecode=Me);function je(e){return(e||"").replace(/^\?/,"")}function Ue(e){const t=e===void 0?typeof window<"u"?window.location.search:"":e,n={},l=je(t);if(!l)return n;const i=new URLSearchParams(l);for(const[a,o]of i.entries())n[a]=o;return n}function We(e){if(!e||typeof window>"u")return null;const t=new URLSearchParams(window.location.search);return t.has(e)?t.get(e):null}function Pe(e,t){if(!e||typeof window>"u")return;const n=new URL(window.location.href);if(t==null||t===""?n.searchParams.delete(e):n.searchParams.set(e,String(t)),n.search===window.location.search)return;const l=n.pathname+n.search+n.hash;window.history.replaceState(window.history.state,"",l)}function Ve(e,t){if(!e||!e.hasAttribute("data-ln-query"))return null;const n=e.getAttribute("data-ln-query");if(n&&n.trim()!=="")return n.trim();const l=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return l?t?l+"_"+t:l:t||null}function He(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ke(e,t){if(e&&typeof e=="string"){if(e.endsWith(".asc"))return{fieldOrColumn:e.slice(0,-4),direction:"asc"};if(e.endsWith(".desc"))return{fieldOrColumn:e.slice(0,-5),direction:"desc"}}if(t&&typeof t=="object"){const n=t.sort_field||t.sort_by;if(n){const l=t.sort_dir&&String(t.sort_dir).toLowerCase()==="desc"?"desc":"asc";return{fieldOrColumn:n,direction:l}}}return null}function Qe(e){return!Array.isArray(e)||e.length===0?null:e.map(encodeURIComponent).join(",")}function Je(e){return!e||typeof e!="string"?[]:e.split(",").map(function(t){try{return decodeURIComponent(t.trim())}catch{return t.trim()}}).filter(Boolean)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.queryParse=Ue,window.lnCore.queryGet=We,window.lnCore.querySet=Pe,window.lnCore.resolveQueryParam=Ve,window.lnCore.querySortEncode=He,window.lnCore.querySortDecode=Ke,window.lnCore.queryFilterEncode=Qe,window.lnCore.queryFilterDecode=Je);function ze(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.uuid=ze);function Ge(e,t,n=""){return!e||!t?"":n?`${n}[trans][${t}][${e}]`:`trans[${t}][${e}]`}function Xe(e,t){return(e||"{lang} translation").replaceAll("{lang}",t||"")}function Ye(e,t){return(e||"Remove {lang}").replaceAll("{lang}",t||"")}function Ze(e,t={}){if(!e)return{...t};if(typeof e=="object"&&e!==null&&!Array.isArray(e))return{...e};if(typeof e=="string")try{const n=JSON.parse(e);if(typeof n=="object"&&n!==null&&!Array.isArray(n))return n}catch{}return{...t}}function ae(e,t={},n=""){if(!e)return"";if(t&&t[e])return t[e];if(typeof Intl<"u"&&typeof Intl.DisplayNames=="function")try{const i=new Intl.DisplayNames(n?[n]:void 0,{type:"language",fallback:"none"}).of(e);if(i)return i}catch{}return e}function et(e,t,n=""){if(!e||typeof e!="object")return[];const l=t instanceof Set?t:new Set(t||[]),i=(n||"").toLowerCase().trim(),a=[];for(const[o,s]of Object.entries(e)){const r=o.toLowerCase().trim();!l.has(o)&&!l.has(r)&&(!i||r!==i)&&a.push([o,s])}return a}(function(){const e="data-ln-translations",t="lnTranslations";if(window[t]!==void 0)return;const n={"data-ln-translations":{type:"marker",description:"Mounts multi-language translation coordinator on form container"},"data-ln-translations-default":{prop:"defaultLang",read:p,type:"string",fallback:"",description:"Default primary language code (e.g. en)"},"data-ln-translations-placeholder":{prop:"placeholderLabel",read:p,type:"string",fallback:"{lang} translation",description:"Placeholder label pattern for cloned translation inputs"},"data-ln-translations-remove-label":{prop:"removeLabel",read:p,type:"string",fallback:"Remove {lang}",description:"Accessible label template for translation removal buttons"},"data-ln-translations-locales":{prop:"_localesRaw",read:E,type:"json",fallback:null,description:"JSON dictionary of supported locale codes and display labels"},"data-ln-translations-dict":{type:"string",description:"Dictionary key prefix mapping for translatable labels"},"data-ln-translations-menu":{type:"marker",description:"Menu container holding available language items"},"data-ln-translations-active":{type:"marker",description:"Container holding active language badge tags"},"data-ln-translations-add":{type:"trigger",description:"Trigger button to open translation language menu"},"data-ln-translations-lang":{type:"string",description:"Language code associated with active language badge or menu item"},"data-ln-translations-prefix":{type:"string",description:"Prefix format pattern for nested translatable field names"},"data-ln-translatable":{type:"string",description:"Marks form control container as translatable, value is field name"},"data-ln-translatable-lang":{type:"string",description:"Language code assigned to specific translatable input instance"}},l=Y(n);function i(a){this.dom=a,X(this,a,l),this.dict=ve(a,"data-ln-translations-dict"),this.locale=pe(a),this.activeLanguages=new Set,this.badgesEl=a.querySelector("[data-ln-translations-active]"),this.menuEl=a.querySelector("[data-ln-translations-menu]")||a.querySelector("[data-ln-dropdown] > [data-ln-toggle]"),this.locales=Ze(this._localesRaw,{}),this._applyDefaultLang();const o=this;return this.menuEl&&(this._boundMenuClick=function(s){if(M(s))return;const r=s.target.closest("button[data-ln-translations-lang]");if(!r||!o.menuEl.contains(r))return;s.preventDefault(),s.stopPropagation();const c=r.getAttribute("data-ln-translations-lang");o.menuEl.getAttribute("data-ln-toggle")==="open"&&o.menuEl.setAttribute("data-ln-toggle","close"),c&&o.addLanguage(c)},this.menuEl.addEventListener("click",this._boundMenuClick)),this.badgesEl&&(this._boundBadgesClick=function(s){if(M(s))return;const r=s.target.closest("button");if(!r||!o.badgesEl.contains(r))return;const c=r.closest("[data-ln-translations-lang]"),u=c?c.getAttribute("data-ln-translations-lang"):null;u&&(s.preventDefault(),s.stopPropagation(),o.removeLanguage(u))},this.badgesEl.addEventListener("click",this._boundBadgesClick)),this._updateDropdown(),this._onRequestAdd=function(s){s.detail&&s.detail.lang&&o.addLanguage(s.detail.lang,s.detail.values)},this._onRequestRemove=function(s){s.detail&&s.detail.lang&&o.removeLanguage(s.detail.lang)},a.addEventListener("ln-translations:request-add",this._onRequestAdd),a.addEventListener("ln-translations:request-remove",this._onRequestRemove),this._detectExisting(),this}i.prototype._applyDefaultLang=function(){if(!this.defaultLang)return;const a=this.dom.querySelectorAll("[data-ln-translatable]");for(const o of a){const s=o.querySelectorAll("input:not([data-ln-translatable-lang]), textarea:not([data-ln-translatable-lang]), select:not([data-ln-translatable-lang])");for(const r of s)r.setAttribute("data-ln-translatable-lang",this.defaultLang)}},i.prototype._detectExisting=function(){const a=this.dom.querySelectorAll("[data-ln-translatable-lang]");for(const o of a){const s=o.getAttribute("data-ln-translatable-lang");s&&s!==this.defaultLang&&this.activeLanguages.add(s)}this.activeLanguages.size>0&&(this._updateBadges(),this._updateDropdown())},i.prototype._updateDropdown=function(){if(!this.menuEl)return;this.menuEl.textContent="";const a=et(this.locales,this.activeLanguages,this.defaultLang);for(let s=0;s<a.length;s++){const[r,c]=a[s],u=W(this.dom,"ln-translations-menu-item")||v("ln-translations-menu-item","ln-translations");if(!u)return;const d=u.querySelector("[data-ln-translations-lang]");d&&(d.setAttribute("data-ln-translations-lang",r),d.textContent=c,this.menuEl.appendChild(u))}const o=this.dom.querySelector("[data-ln-translations-add]");o&&(o.hidden=a.length===0)},i.prototype._updateBadges=function(){if(!this.badgesEl)return;this.badgesEl.textContent="";const a=this,o=this.dict&&this.dict["remove-label"]||this.removeLabel;this.activeLanguages.forEach(function(s){const r=W(a.dom,"ln-translations-badge")||v("ln-translations-badge","ln-translations");if(!r)return;const c=r.querySelector("[data-ln-translations-lang]");if(!c)return;c.setAttribute("data-ln-translations-lang",s);const u=ae(s,a.locales,a.locale),d=c.querySelector("span");d&&(d.textContent=u);const f=c.querySelector("button");f&&f.setAttribute("aria-label",Ye(o,u)),a.badgesEl.appendChild(r)})},i.prototype.addLanguage=function(a,o){if(!a||a===this.defaultLang||this.activeLanguages.has(a))return;const s=ae(a,this.locales,this.locale);if($(this.dom,"ln-translations:before-add",{target:this.dom,lang:a,langName:s}).defaultPrevented)return;this.activeLanguages.add(a),o=o||{};const c=this.dict&&this.dict.placeholder||this.placeholderLabel,u=Xe(c,s),d=this.dom.querySelectorAll("[data-ln-translatable]");for(const f of d){const b=f.getAttribute("data-ln-translatable"),R=f.getAttribute("data-ln-translations-prefix")||"",h=f.querySelector('[data-ln-translatable-lang="'+this.defaultLang+'"]')||f.querySelector("input, textarea, select");if(!h)continue;const g=h.cloneNode(h.tagName==="SELECT");g.name=Ge(b,a,R),g.value=o[b]!==void 0?o[b]:"",g.removeAttribute("id"),"placeholder"in g&&(g.placeholder=u),g.setAttribute("aria-label",u),g.setAttribute("data-ln-translatable-lang",a);const m=f.querySelectorAll("[data-ln-translatable-lang]"),y=m.length>0?m[m.length-1]:h;y.parentNode.insertBefore(g,y.nextSibling)}this._updateDropdown(),this._updateBadges(),x(this.dom,"ln-translations:added",{target:this.dom,lang:a,langName:s})},i.prototype.removeLanguage=function(a){if(!a||a===this.defaultLang||!this.activeLanguages.has(a)||$(this.dom,"ln-translations:before-remove",{target:this.dom,lang:a}).defaultPrevented)return;const s=this.dom.querySelectorAll('[data-ln-translatable-lang="'+a+'"]');for(const r of s)r.parentNode.removeChild(r);this.activeLanguages.delete(a),this._updateDropdown(),this._updateBadges(),x(this.dom,"ln-translations:removed",{target:this.dom,lang:a})},i.prototype.getActiveLanguages=function(){return new Set(this.activeLanguages)},i.prototype.hasLanguage=function(a){return this.activeLanguages.has(a)},i.prototype.destroy=function(){if(!this.dom[t])return;for(const o of this.activeLanguages){const s=this.dom.querySelectorAll('[data-ln-translatable-lang="'+o+'"]');for(const r of s)r.parentNode.removeChild(r)}this.badgesEl&&(this.badgesEl.textContent="",this._boundBadgesClick&&(this.badgesEl.removeEventListener("click",this._boundBadgesClick),this._boundBadgesClick=null)),this.menuEl&&(this.menuEl.textContent="",this._boundMenuClick&&(this.menuEl.removeEventListener("click",this._boundMenuClick),this._boundMenuClick=null));const a=this.dom.querySelector("[data-ln-translations-add]");a&&(a.hidden=!1),this.dom.removeEventListener("ln-translations:request-add",this._onRequestAdd),this.dom.removeEventListener("ln-translations:request-remove",this._onRequestRemove),this.activeLanguages.clear(),delete this.dom[t]},ie(e,t,i,"ln-translations",{attributes:n})})()})();