@livenetworks/ashlar 1.6.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. package/LICENSE +641 -0
  2. package/README.md +202 -86
  3. package/{js → components}/COMPONENTS.md +1116 -1108
  4. package/{js → components}/index.js +81 -58
  5. package/{js → components}/ln-accordion/README.md +7 -6
  6. package/components/ln-accordion/ln-accordion-dev.scss +8 -0
  7. package/components/ln-accordion/ln-accordion.js +1 -0
  8. package/components/ln-accordion/ln-accordion.schema.json +30 -0
  9. package/components/ln-accordion/ln-accordion.scss +8 -0
  10. package/{js → components}/ln-accordion/src/ln-accordion.js +8 -2
  11. package/{js → components}/ln-ajax/README.md +171 -160
  12. package/components/ln-ajax/ln-ajax-dev.scss +8 -0
  13. package/components/ln-ajax/ln-ajax.js +1 -0
  14. package/components/ln-ajax/ln-ajax.schema.json +30 -0
  15. package/{js → components}/ln-ajax/src/ln-ajax.js +65 -30
  16. package/{js → components}/ln-api-connector/README.md +27 -5
  17. package/components/ln-api-connector/ln-api-connector.js +1 -0
  18. package/components/ln-api-connector/ln-api-connector.schema.json +96 -0
  19. package/components/ln-api-connector/src/connector-core.js +97 -0
  20. package/components/ln-api-connector/src/ln-api-connector.js +447 -0
  21. package/{js → components}/ln-api-queue/README.md +12 -9
  22. package/components/ln-api-queue/ln-api-queue.js +1 -0
  23. package/components/ln-api-queue/ln-api-queue.schema.json +34 -0
  24. package/{js → components}/ln-api-queue/src/ln-api-queue.js +33 -14
  25. package/{js → components}/ln-api-queue/src/queue-storage.js +7 -3
  26. package/{js → components}/ln-autoresize/README.md +129 -127
  27. package/components/ln-autoresize/ln-autoresize-dev.scss +8 -0
  28. package/components/ln-autoresize/ln-autoresize.js +1 -0
  29. package/components/ln-autoresize/ln-autoresize.schema.json +22 -0
  30. package/{js → components}/ln-autoresize/src/ln-autoresize.js +8 -1
  31. package/{js → components}/ln-autosave/README.md +127 -124
  32. package/components/ln-autosave/ln-autosave-dev.scss +13 -0
  33. package/components/ln-autosave/ln-autosave.js +1 -0
  34. package/components/ln-autosave/ln-autosave.schema.json +48 -0
  35. package/components/ln-autosave/src/autosave-model.js +34 -0
  36. package/{js → components}/ln-autosave/src/ln-autosave.js +65 -58
  37. package/components/ln-chart/README.md +145 -0
  38. package/components/ln-chart/ln-chart-dev.scss +20 -0
  39. package/components/ln-chart/ln-chart.js +1 -0
  40. package/components/ln-chart/ln-chart.schema.json +146 -0
  41. package/components/ln-chart/ln-chart.scss +8 -0
  42. package/components/ln-chart/src/chart-model.js +154 -0
  43. package/components/ln-chart/src/ln-chart.js +176 -0
  44. package/{js → components}/ln-circular-progress/README.md +15 -14
  45. package/components/ln-circular-progress/ln-circular-progress-dev.scss +8 -0
  46. package/components/ln-circular-progress/ln-circular-progress.js +1 -0
  47. package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -0
  48. package/{js → components}/ln-circular-progress/src/ln-circular-progress.js +32 -50
  49. package/{js → components}/ln-confirm/README.md +69 -18
  50. package/components/ln-confirm/ln-confirm-dev.scss +24 -0
  51. package/components/ln-confirm/ln-confirm.js +1 -0
  52. package/components/ln-confirm/ln-confirm.schema.json +66 -0
  53. package/components/ln-confirm/ln-confirm.scss +24 -0
  54. package/{js → components}/ln-confirm/src/ln-confirm.js +180 -171
  55. package/{js → components}/ln-core/README.md +374 -149
  56. package/components/ln-core/attrs.js +273 -0
  57. package/components/ln-core/compare.js +40 -0
  58. package/components/ln-core/crypto.js +265 -0
  59. package/components/ln-core/date.js +50 -0
  60. package/components/ln-core/dom.js +115 -0
  61. package/components/ln-core/events.js +122 -0
  62. package/components/ln-core/form.js +136 -0
  63. package/{js → components}/ln-core/hash.js +149 -92
  64. package/components/ln-core/helpers.js +33 -0
  65. package/components/ln-core/http.js +48 -0
  66. package/components/ln-core/index.js +11 -0
  67. package/components/ln-core/lifecycle.js +403 -0
  68. package/components/ln-core/ln-core.schema.json +109 -0
  69. package/components/ln-core/locale.js +55 -0
  70. package/components/ln-core/matching.js +78 -0
  71. package/components/ln-core/number.js +125 -0
  72. package/components/ln-core/progress.js +30 -0
  73. package/components/ln-core/template.js +206 -0
  74. package/{js → components}/ln-core/window-cache.js +247 -213
  75. package/{js → components}/ln-couchdb-connector/README.md +7 -5
  76. package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
  77. package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -0
  78. package/{js → components}/ln-couchdb-connector/src/ln-couchdb-connector.js +29 -43
  79. package/{js → components}/ln-data-coordinator/README.md +109 -73
  80. package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -0
  81. package/components/ln-data-coordinator/ln-data-coordinator.js +1 -0
  82. package/components/ln-data-coordinator/ln-data-coordinator.schema.json +196 -0
  83. package/components/ln-data-coordinator/src/data-read-policy.js +41 -0
  84. package/{js → components}/ln-data-coordinator/src/ln-data-coordinator.js +411 -154
  85. package/{js → components}/ln-data-coordinator/src/mutation-receipts.js +0 -5
  86. package/{js → components}/ln-data-store/README.md +42 -17
  87. package/components/ln-data-store/ln-data-store-dev.scss +13 -0
  88. package/components/ln-data-store/ln-data-store.js +1 -0
  89. package/components/ln-data-store/ln-data-store.schema.json +84 -0
  90. package/components/ln-data-store/src/data-store-model.js +155 -0
  91. package/{js → components}/ln-data-store/src/ln-data-store.js +407 -105
  92. package/components/ln-data-store/src/window-index.js +119 -0
  93. package/{js → components}/ln-date/README.md +17 -7
  94. package/{js → components}/ln-date/ln-date-dev.scss +14 -14
  95. package/components/ln-date/ln-date.js +1 -0
  96. package/components/ln-date/ln-date.schema.json +92 -0
  97. package/components/ln-date/src/date-model.js +186 -0
  98. package/components/ln-date/src/ln-date.js +486 -0
  99. package/components/ln-debug/README.md +132 -0
  100. package/components/ln-debug/ln-debug.js +1 -0
  101. package/components/ln-debug/ln-debug.schema.json +28 -0
  102. package/components/ln-debug/src/console-sink.js +19 -0
  103. package/components/ln-debug/src/debug-verifier.js +331 -0
  104. package/components/ln-debug/src/gate.js +95 -0
  105. package/components/ln-debug/src/generated-attributes.js +299 -0
  106. package/components/ln-debug/src/ln-debug.js +60 -0
  107. package/{js → components}/ln-dropdown/README.md +150 -140
  108. package/components/ln-dropdown/ln-dropdown-dev.scss +13 -0
  109. package/components/ln-dropdown/ln-dropdown.js +1 -0
  110. package/components/ln-dropdown/ln-dropdown.schema.json +90 -0
  111. package/components/ln-dropdown/ln-dropdown.scss +18 -0
  112. package/{js → components}/ln-dropdown/src/ln-dropdown.js +114 -11
  113. package/{js → components}/ln-editor/README.md +11 -9
  114. package/components/ln-editor/ln-editor-dev.scss +18 -0
  115. package/components/ln-editor/ln-editor.js +1 -0
  116. package/components/ln-editor/ln-editor.schema.json +58 -0
  117. package/components/ln-editor/ln-editor.scss +13 -0
  118. package/{js → components}/ln-editor/src/ln-editor.js +59 -11
  119. package/{js → components}/ln-external-links/README.md +10 -8
  120. package/components/ln-external-links/ln-external-links.js +1 -0
  121. package/components/ln-external-links/ln-external-links.schema.json +18 -0
  122. package/{js → components}/ln-external-links/src/ln-external-links.js +13 -11
  123. package/{js → components}/ln-fill/README.md +6 -8
  124. package/components/ln-fill/ln-fill.js +1 -0
  125. package/components/ln-fill/ln-fill.schema.json +23 -0
  126. package/{js → components}/ln-fill/src/ln-fill.js +7 -1
  127. package/components/ln-filter/README.md +131 -0
  128. package/components/ln-filter/ln-filter-dev.scss +13 -0
  129. package/components/ln-filter/ln-filter.js +1 -0
  130. package/components/ln-filter/ln-filter.schema.json +153 -0
  131. package/components/ln-filter/src/filter-model.js +185 -0
  132. package/components/ln-filter/src/ln-filter.js +435 -0
  133. package/{js → components}/ln-form/README.md +260 -264
  134. package/components/ln-form/ln-form-dev.scss +8 -0
  135. package/components/ln-form/ln-form.js +1 -0
  136. package/components/ln-form/ln-form.schema.json +45 -0
  137. package/{js → components}/ln-form/src/ln-form.js +107 -99
  138. package/{js → components}/ln-http/README.md +11 -6
  139. package/components/ln-http/ln-http.js +1 -0
  140. package/components/ln-http/ln-http.schema.json +6 -0
  141. package/components/ln-http/src/http-core.js +51 -0
  142. package/{js → components}/ln-http/src/ln-http.js +28 -33
  143. package/{js → components}/ln-icon/README.md +16 -9
  144. package/components/ln-icon/ln-icon.schema.json +6 -0
  145. package/components/ln-include/README.md +75 -0
  146. package/components/ln-include/ln-include-dev.scss +13 -0
  147. package/components/ln-include/ln-include.js +1 -0
  148. package/components/ln-include/ln-include.schema.json +23 -0
  149. package/components/ln-include/src/ln-include.js +111 -0
  150. package/components/ln-key/README.md +130 -0
  151. package/components/ln-key/ln-key-dev.scss +18 -0
  152. package/components/ln-key/ln-key.js +1 -0
  153. package/components/ln-key/ln-key.schema.json +56 -0
  154. package/components/ln-key/src/key-model.js +146 -0
  155. package/components/ln-key/src/ln-key.js +201 -0
  156. package/{js → components}/ln-link/README.md +7 -9
  157. package/components/ln-link/ln-link-dev.scss +8 -0
  158. package/components/ln-link/ln-link.js +1 -0
  159. package/components/ln-link/ln-link.schema.json +22 -0
  160. package/{js → components}/ln-link/src/ln-link.js +16 -11
  161. package/components/ln-list/README.md +152 -0
  162. package/components/ln-list/ln-list-dev.scss +8 -0
  163. package/components/ln-list/ln-list.js +1 -0
  164. package/components/ln-list/ln-list.schema.json +166 -0
  165. package/components/ln-list/ln-list.scss +25 -0
  166. package/{js → components}/ln-list/src/ln-list.js +1301 -1216
  167. package/{js → components}/ln-modal/README.md +13 -10
  168. package/components/ln-modal/ln-modal-dev.scss +18 -0
  169. package/components/ln-modal/ln-modal.js +1 -0
  170. package/components/ln-modal/ln-modal.schema.json +54 -0
  171. package/components/ln-modal/ln-modal.scss +51 -0
  172. package/{js → components}/ln-modal/src/ln-modal.js +164 -137
  173. package/{js → components}/ln-nav/README.md +11 -11
  174. package/components/ln-nav/ln-nav.js +1 -0
  175. package/components/ln-nav/ln-nav.schema.json +25 -0
  176. package/{js → components}/ln-nav/src/ln-nav.js +25 -14
  177. package/components/ln-number/README.md +205 -0
  178. package/{js → components}/ln-number/ln-number-dev.scss +13 -13
  179. package/components/ln-number/ln-number.js +1 -0
  180. package/components/ln-number/ln-number.schema.json +63 -0
  181. package/components/ln-number/src/ln-number.js +400 -0
  182. package/components/ln-number/src/number-model.js +31 -0
  183. package/components/ln-obfuscator/README.md +60 -0
  184. package/components/ln-obfuscator/ln-obfuscator.js +1 -0
  185. package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -0
  186. package/components/ln-obfuscator/src/ln-obfuscator.js +159 -0
  187. package/components/ln-obfuscator/src/obfuscator-model.js +250 -0
  188. package/{js → components}/ln-options/README.md +3 -1
  189. package/components/ln-options/ln-options-dev.scss +13 -0
  190. package/components/ln-options/ln-options.js +1 -0
  191. package/components/ln-options/ln-options.schema.json +41 -0
  192. package/{js → components}/ln-options/src/ln-options.js +13 -5
  193. package/components/ln-persist/README.md +151 -0
  194. package/components/ln-persist/ln-persist.js +1 -0
  195. package/components/ln-persist/ln-persist.schema.json +28 -0
  196. package/components/ln-persist/src/ln-persist.js +83 -0
  197. package/components/ln-picklist/README.md +230 -0
  198. package/components/ln-picklist/ln-picklist-dev.scss +22 -0
  199. package/components/ln-picklist/ln-picklist.js +1 -0
  200. package/components/ln-picklist/ln-picklist.schema.json +49 -0
  201. package/components/ln-picklist/src/ln-picklist.js +228 -0
  202. package/{js → components}/ln-popover/README.md +164 -162
  203. package/components/ln-popover/ln-popover-dev.scss +13 -0
  204. package/components/ln-popover/ln-popover.js +1 -0
  205. package/components/ln-popover/ln-popover.schema.json +82 -0
  206. package/components/ln-popover/ln-popover.scss +18 -0
  207. package/{js → components}/ln-popover/src/ln-popover.js +42 -36
  208. package/{js → components}/ln-progress/README.md +410 -413
  209. package/components/ln-progress/ln-progress-dev.scss +8 -0
  210. package/components/ln-progress/ln-progress.js +1 -0
  211. package/components/ln-progress/ln-progress.schema.json +40 -0
  212. package/components/ln-progress/src/ln-progress.js +91 -0
  213. package/components/ln-progress/src/progress-model.js +20 -0
  214. package/{js → components}/ln-router/README.md +443 -432
  215. package/components/ln-router/ln-router-dev.scss +13 -0
  216. package/components/ln-router/ln-router.js +1 -0
  217. package/components/ln-router/ln-router.schema.json +68 -0
  218. package/{js → components}/ln-router/src/ln-router.js +585 -539
  219. package/components/ln-router/src/router-model.js +50 -0
  220. package/components/ln-scroll/README.md +45 -0
  221. package/components/ln-scroll/ln-scroll.js +1 -0
  222. package/components/ln-scroll/ln-scroll.schema.json +85 -0
  223. package/components/ln-scroll/src/ln-scroll.js +150 -0
  224. package/components/ln-search/README.md +188 -0
  225. package/components/ln-search/ln-search-dev.scss +13 -0
  226. package/components/ln-search/ln-search.js +1 -0
  227. package/components/ln-search/ln-search.schema.json +103 -0
  228. package/components/ln-search/src/ln-search.js +330 -0
  229. package/{js → components}/ln-slug/README.md +6 -3
  230. package/components/ln-slug/ln-slug-dev.scss +18 -0
  231. package/components/ln-slug/ln-slug.js +1 -0
  232. package/components/ln-slug/ln-slug.schema.json +23 -0
  233. package/{js → components}/ln-slug/src/ln-slug.js +20 -13
  234. package/components/ln-slug/src/slug-model.js +21 -0
  235. package/{js → components}/ln-sort/README.md +178 -170
  236. package/{js → components}/ln-sort/ln-sort-dev.scss +8 -8
  237. package/components/ln-sort/ln-sort.js +1 -0
  238. package/components/ln-sort/ln-sort.schema.json +104 -0
  239. package/components/ln-sort/src/ln-sort.js +321 -0
  240. package/components/ln-sort/src/sort-model.js +117 -0
  241. package/{js → components}/ln-sortable/README.md +7 -11
  242. package/components/ln-sortable/ln-sortable-dev.scss +13 -0
  243. package/components/ln-sortable/ln-sortable.js +1 -0
  244. package/components/ln-sortable/ln-sortable.schema.json +36 -0
  245. package/{js → components}/ln-sortable/src/ln-sortable.js +8 -13
  246. package/{js → components}/ln-stat/README.md +3 -1
  247. package/components/ln-stat/ln-stat-dev.scss +8 -0
  248. package/components/ln-stat/ln-stat.js +1 -0
  249. package/components/ln-stat/ln-stat.schema.json +32 -0
  250. package/{js → components}/ln-stat/src/ln-stat.js +14 -18
  251. package/components/ln-stat/src/stat-model.js +28 -0
  252. package/{js → components}/ln-table/README.md +37 -24
  253. package/{js → components}/ln-table/ln-table-dev.scss +17 -17
  254. package/components/ln-table/ln-table.js +1 -0
  255. package/components/ln-table/ln-table.schema.json +211 -0
  256. package/components/ln-table/ln-table.scss +15 -0
  257. package/{js → components}/ln-table/src/ln-table.js +1365 -1493
  258. package/components/ln-table/src/table-model.js +98 -0
  259. package/components/ln-table-coordinator/README.md +61 -0
  260. package/components/ln-table-coordinator/ln-table-coordinator.js +1 -0
  261. package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -0
  262. package/components/ln-table-coordinator/src/ln-table-coordinator.js +193 -0
  263. package/{js → components}/ln-tabs/README.md +32 -14
  264. package/components/ln-tabs/ln-tabs-dev.scss +24 -0
  265. package/components/ln-tabs/ln-tabs.js +1 -0
  266. package/components/ln-tabs/ln-tabs.schema.json +75 -0
  267. package/components/ln-tabs/ln-tabs.scss +8 -0
  268. package/components/ln-tabs/src/ln-tabs.js +207 -0
  269. package/components/ln-tabs/src/tabs-model.js +82 -0
  270. package/{js → components}/ln-time/README.md +96 -95
  271. package/components/ln-time/ln-time-dev.scss +13 -0
  272. package/components/ln-time/ln-time.js +1 -0
  273. package/components/ln-time/ln-time.schema.json +38 -0
  274. package/{js → components}/ln-time/src/ln-time.js +206 -223
  275. package/components/ln-time/src/time-model.js +64 -0
  276. package/{js → components}/ln-toast/README.md +23 -5
  277. package/components/ln-toast/ln-toast-dev.scss +8 -0
  278. package/components/ln-toast/ln-toast.js +1 -0
  279. package/components/ln-toast/ln-toast.schema.json +65 -0
  280. package/components/ln-toast/ln-toast.scss +59 -0
  281. package/{js → components}/ln-toast/src/ln-toast.js +233 -232
  282. package/{js → components}/ln-toggle/README.md +198 -196
  283. package/{js → components}/ln-toggle/ln-toggle-dev.scss +13 -13
  284. package/components/ln-toggle/ln-toggle.js +1 -0
  285. package/components/ln-toggle/ln-toggle.schema.json +52 -0
  286. package/components/ln-toggle/ln-toggle.scss +37 -0
  287. package/{js → components}/ln-toggle/src/ln-toggle.js +61 -46
  288. package/{js → components}/ln-tooltip/README.md +6 -6
  289. package/{js → components}/ln-tooltip/ln-tooltip-dev.scss +9 -9
  290. package/components/ln-tooltip/ln-tooltip.js +1 -0
  291. package/components/ln-tooltip/ln-tooltip.schema.json +86 -0
  292. package/components/ln-tooltip/ln-tooltip.scss +9 -0
  293. package/{js → components}/ln-tooltip/src/ln-tooltip.js +14 -3
  294. package/{js → components}/ln-translations/README.md +3 -1
  295. package/components/ln-translations/ln-translations-dev.scss +13 -0
  296. package/components/ln-translations/ln-translations.js +1 -0
  297. package/components/ln-translations/ln-translations.schema.json +120 -0
  298. package/{js → components}/ln-translations/src/ln-translations.js +25 -10
  299. package/components/ln-ui-coordinator/README.md +101 -0
  300. package/components/ln-ui-coordinator/ln-ui-coordinator-dev.scss +8 -0
  301. package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -0
  302. package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +60 -0
  303. package/{js/ln-modal-coordinator/src/ln-modal-coordinator.js → components/ln-ui-coordinator/src/ln-ui-coordinator.js} +403 -345
  304. package/components/ln-upload/README.md +133 -0
  305. package/components/ln-upload/ln-upload-dev.scss +18 -0
  306. package/components/ln-upload/ln-upload.js +1 -0
  307. package/components/ln-upload/ln-upload.schema.json +193 -0
  308. package/components/ln-upload/ln-upload.scss +20 -0
  309. package/components/ln-upload/src/ln-upload.js +652 -0
  310. package/components/ln-upload/src/upload-model.js +78 -0
  311. package/{js → components}/ln-validate/README.md +182 -180
  312. package/{js → components}/ln-validate/ln-validate-dev.scss +15 -15
  313. package/components/ln-validate/ln-validate.js +1 -0
  314. package/components/ln-validate/ln-validate.schema.json +50 -0
  315. package/components/ln-validate/ln-validate.scss +7 -0
  316. package/{js → components}/ln-validate/src/ln-validate.js +23 -45
  317. package/components/ln-validate/src/validate-model.js +64 -0
  318. package/components/ln-websocket-connector/README.md +166 -0
  319. package/components/ln-websocket-connector/ln-websocket-connector.js +1 -0
  320. package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -0
  321. package/components/ln-websocket-connector/src/ln-websocket-connector.js +279 -0
  322. package/ln-ashlar.html-data.json +1796 -0
  323. package/package.json +84 -61
  324. package/{scss → theme}/base/_global.scss +1 -2
  325. package/{scss → theme}/base/_reset.scss +1 -1
  326. package/{scss → theme}/base/_typography.scss +2 -0
  327. package/theme/brand.css +73 -0
  328. package/{scss → theme}/components/_app-shell.scss +8 -0
  329. package/theme/components/_button.scss +24 -0
  330. package/theme/components/_chart.scss +5 -0
  331. package/theme/components/_confirm.scss +6 -0
  332. package/{scss → theme}/components/_date.scss +30 -22
  333. package/{scss → theme}/components/_dropdown.scss +6 -1
  334. package/theme/components/_form.scss +140 -0
  335. package/{scss → theme}/components/_layout.scss +6 -0
  336. package/{scss → theme}/components/_ln-table.scss +1 -6
  337. package/theme/components/_picklist.scss +3 -0
  338. package/{scss → theme}/components/_sort.scss +10 -10
  339. package/theme/components/_status-badge.scss +6 -0
  340. package/{scss → theme}/components/_table.scss +16 -0
  341. package/{scss → theme}/components/_tabs.scss +0 -4
  342. package/theme/components/_toast.scss +48 -0
  343. package/{scss → theme}/components/_toggle.scss +1 -1
  344. package/theme/components/_upload.scss +45 -0
  345. package/{scss → theme}/config/_breakpoints.scss +1 -1
  346. package/theme/config/_contrast.scss +128 -0
  347. package/{scss → theme}/config/_density.scss +191 -205
  348. package/theme/config/_palette.scss +274 -0
  349. package/theme/config/_theme.scss +293 -0
  350. package/{scss → theme}/config/_tokens.scss +285 -441
  351. package/{scss → theme}/config/mixins/_accordion.scss +1 -1
  352. package/{scss → theme}/config/mixins/_alert.scss +1 -0
  353. package/{scss → theme}/config/mixins/_app-shell.scss +4 -2
  354. package/{scss → theme}/config/mixins/_borders.scss +2 -0
  355. package/theme/config/mixins/_btn.scss +175 -0
  356. package/{scss → theme}/config/mixins/_card.scss +55 -46
  357. package/theme/config/mixins/_chart.scss +82 -0
  358. package/{scss → theme}/config/mixins/_collapsible.scss +2 -1
  359. package/{scss → theme}/config/mixins/_colors.scss +8 -14
  360. package/{scss → theme}/config/mixins/_diagnostics.scss +48 -48
  361. package/theme/config/mixins/_dropdown.scss +169 -0
  362. package/{scss → theme}/config/mixins/_editor.scss +0 -7
  363. package/{scss → theme}/config/mixins/_filter.scss +47 -47
  364. package/{scss → theme}/config/mixins/_footer.scss +1 -1
  365. package/{scss → theme}/config/mixins/_form.scss +49 -18
  366. package/{scss → theme}/config/mixins/_index.scss +62 -61
  367. package/{scss → theme}/config/mixins/_layout.scss +6 -2
  368. package/{scss → theme}/config/mixins/_ln-table.scss +31 -10
  369. package/{scss → theme}/config/mixins/_loader.scss +1 -1
  370. package/{scss → theme}/config/mixins/_modal.scss +145 -149
  371. package/{scss → theme}/config/mixins/_motion.scss +13 -0
  372. package/{scss → theme}/config/mixins/_nav.scss +7 -7
  373. package/theme/config/mixins/_picklist.scss +66 -0
  374. package/theme/config/mixins/_popover.scss +96 -0
  375. package/{scss → theme}/config/mixins/_sidebar.scss +7 -4
  376. package/{scss → theme}/config/mixins/_sort.scss +43 -42
  377. package/{scss → theme}/config/mixins/_status-badge.scss +15 -2
  378. package/{scss → theme}/config/mixins/_table.scss +25 -14
  379. package/{scss → theme}/config/mixins/_tabs.scss +1 -1
  380. package/{scss → theme}/config/mixins/_toast.scss +174 -179
  381. package/{scss → theme}/config/mixins/_tooltip.scss +2 -2
  382. package/{scss → theme}/config/mixins/_typography.scss +16 -5
  383. package/{scss → theme}/config/mixins/_upload.scss +8 -6
  384. package/theme/ln-ashlar-core.scss +24 -0
  385. package/theme/ln-ashlar-dev.scss +66 -0
  386. package/theme/ln-ashlar-landing.scss +56 -0
  387. package/{scss/ln-ashlar.scss → theme/ln-ashlar-theme.scss} +63 -69
  388. package/theme/ln-ashlar.scss +8 -0
  389. package/theme/presentation/_bento.scss +151 -0
  390. package/theme/presentation/_cta.scss +111 -0
  391. package/theme/presentation/_effects.scss +216 -0
  392. package/theme/presentation/_features.scss +108 -0
  393. package/theme/presentation/_footer.scss +129 -0
  394. package/theme/presentation/_hero.scss +158 -0
  395. package/theme/presentation/_layout.scss +170 -0
  396. package/theme/presentation/_navbar.scss +140 -0
  397. package/theme/presentation/_pricing.scss +262 -0
  398. package/theme/presentation/_stats.scss +87 -0
  399. package/theme/presentation/_testimonials.scss +124 -0
  400. package/theme/presentation/_tokens.scss +39 -0
  401. package/theme/presentation/_typography.scss +163 -0
  402. package/{scss → theme}/utilities/_animations.scss +38 -0
  403. package/{scss → theme}/utilities/_utilities.scss +6 -0
  404. package/web-types.json +2312 -0
  405. package/js/ln-accordion/ln-accordion.js +0 -1
  406. package/js/ln-ajax/ln-ajax.js +0 -1
  407. package/js/ln-api-connector/ln-api-connector.js +0 -1
  408. package/js/ln-api-connector/src/ln-api-connector.js +0 -368
  409. package/js/ln-api-queue/ln-api-queue.js +0 -1
  410. package/js/ln-autoresize/ln-autoresize.js +0 -1
  411. package/js/ln-autosave/ln-autosave.js +0 -1
  412. package/js/ln-circular-progress/ln-circular-progress.js +0 -1
  413. package/js/ln-confirm/_ln-confirm.scss +0 -24
  414. package/js/ln-confirm/ln-confirm.js +0 -1
  415. package/js/ln-core/crypto.js +0 -83
  416. package/js/ln-core/helpers.js +0 -788
  417. package/js/ln-core/index.js +0 -7
  418. package/js/ln-core/persist.js +0 -97
  419. package/js/ln-couchdb-connector/ln-couchdb-connector.js +0 -1
  420. package/js/ln-data-coordinator/ln-data-coordinator.js +0 -1
  421. package/js/ln-data-coordinator/src/data-read-policy.js +0 -18
  422. package/js/ln-data-store/ln-data-store.js +0 -1
  423. package/js/ln-date/ln-date.js +0 -1
  424. package/js/ln-date/src/ln-date.js +0 -603
  425. package/js/ln-debug/README.md +0 -58
  426. package/js/ln-debug/ln-debug.js +0 -1
  427. package/js/ln-debug/src/ln-debug.js +0 -19
  428. package/js/ln-dropdown/ln-dropdown.js +0 -1
  429. package/js/ln-dropdown/ln-dropdown.scss +0 -15
  430. package/js/ln-editor/ln-editor.js +0 -1
  431. package/js/ln-editor/ln-editor.scss +0 -43
  432. package/js/ln-external-links/ln-external-links.js +0 -1
  433. package/js/ln-fill/ln-fill.js +0 -1
  434. package/js/ln-filter/README.md +0 -189
  435. package/js/ln-filter/ln-filter-dev.scss +0 -8
  436. package/js/ln-filter/ln-filter.js +0 -1
  437. package/js/ln-filter/src/ln-filter.js +0 -419
  438. package/js/ln-form/ln-form.js +0 -1
  439. package/js/ln-http/ln-http.js +0 -1
  440. package/js/ln-link/ln-link.js +0 -1
  441. package/js/ln-list/README.md +0 -129
  442. package/js/ln-list/ln-list.js +0 -1
  443. package/js/ln-list/ln-list.scss +0 -28
  444. package/js/ln-modal/ln-modal-dev.scss +0 -13
  445. package/js/ln-modal/ln-modal.js +0 -1
  446. package/js/ln-modal/ln-modal.scss +0 -35
  447. package/js/ln-modal-coordinator/README.md +0 -99
  448. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +0 -8
  449. package/js/ln-modal-coordinator/ln-modal-coordinator.js +0 -1
  450. package/js/ln-nav/ln-nav.js +0 -1
  451. package/js/ln-number/README.md +0 -149
  452. package/js/ln-number/ln-number.js +0 -1
  453. package/js/ln-number/src/ln-number.js +0 -443
  454. package/js/ln-options/ln-options.js +0 -1
  455. package/js/ln-popover/ln-popover.js +0 -1
  456. package/js/ln-progress/ln-progress.js +0 -1
  457. package/js/ln-progress/src/ln-progress.js +0 -98
  458. package/js/ln-router/ln-router.js +0 -1
  459. package/js/ln-search/README.md +0 -158
  460. package/js/ln-search/ln-search-dev.scss +0 -8
  461. package/js/ln-search/ln-search.js +0 -1
  462. package/js/ln-search/src/ln-search.js +0 -117
  463. package/js/ln-slug/ln-slug.js +0 -1
  464. package/js/ln-sort/ln-sort.js +0 -1
  465. package/js/ln-sort/src/ln-sort.js +0 -178
  466. package/js/ln-sortable/ln-sortable.js +0 -1
  467. package/js/ln-stat/ln-stat.js +0 -1
  468. package/js/ln-table/ln-table.js +0 -1
  469. package/js/ln-table/ln-table.scss +0 -11
  470. package/js/ln-table-coordinator/README.md +0 -73
  471. package/js/ln-table-coordinator/ln-table-coordinator.js +0 -1
  472. package/js/ln-table-coordinator/src/ln-table-coordinator.js +0 -160
  473. package/js/ln-tabs/ln-tabs-dev.scss +0 -18
  474. package/js/ln-tabs/ln-tabs.js +0 -1
  475. package/js/ln-tabs/src/ln-tabs.js +0 -188
  476. package/js/ln-time/ln-time.js +0 -1
  477. package/js/ln-toast/ln-toast.js +0 -1
  478. package/js/ln-toggle/ln-toggle.js +0 -1
  479. package/js/ln-tooltip/ln-tooltip.js +0 -1
  480. package/js/ln-tooltip/ln-tooltip.scss +0 -9
  481. package/js/ln-translations/ln-translations.js +0 -1
  482. package/js/ln-upload/README.md +0 -255
  483. package/js/ln-upload/ln-upload.js +0 -1
  484. package/js/ln-upload/ln-upload.scss +0 -20
  485. package/js/ln-upload/src/ln-upload.js +0 -423
  486. package/js/ln-validate/ln-validate.js +0 -1
  487. package/scss/components/_button.scss +0 -20
  488. package/scss/components/_confirm.scss +0 -5
  489. package/scss/components/_form.scss +0 -107
  490. package/scss/components/_status-badge.scss +0 -4
  491. package/scss/components/_toast.scss +0 -68
  492. package/scss/components/_upload.scss +0 -51
  493. package/scss/config/_theme.scss +0 -216
  494. package/scss/config/mixins/_btn.scss +0 -179
  495. package/scss/config/mixins/_confirm.scss +0 -31
  496. package/scss/config/mixins/_dropdown.scss +0 -141
  497. package/scss/config/mixins/_popover.scss +0 -64
  498. package/scss/ln-ashlar-dev.scss +0 -39
  499. /package/{js → components}/ln-core/positioning.js +0 -0
  500. /package/{js → components}/ln-core/reactive.js +0 -0
  501. /package/{js → components}/ln-filter/ln-filter.scss +0 -0
  502. /package/{js → components}/ln-icon/ln-icon.js +0 -0
  503. /package/{js → components}/ln-icon/src/ln-icon.js +0 -0
  504. /package/{js → components}/ln-search/ln-search.scss +0 -0
  505. /package/{js → components}/ln-toast/template.html +0 -0
  506. /package/{scss → theme}/components/_accordion.scss +0 -0
  507. /package/{scss → theme}/components/_ajax.scss +0 -0
  508. /package/{scss → theme}/components/_alert.scss +0 -0
  509. /package/{scss → theme}/components/_avatar.scss +0 -0
  510. /package/{scss → theme}/components/_breadcrumbs.scss +0 -0
  511. /package/{scss → theme}/components/_card.scss +0 -0
  512. /package/{scss → theme}/components/_chip.scss +0 -0
  513. /package/{scss → theme}/components/_circular-progress.scss +0 -0
  514. /package/{scss → theme}/components/_editor.scss +0 -0
  515. /package/{scss → theme}/components/_empty-state.scss +0 -0
  516. /package/{scss → theme}/components/_filter.scss +0 -0
  517. /package/{scss → theme}/components/_link.scss +0 -0
  518. /package/{scss → theme}/components/_loader.scss +0 -0
  519. /package/{scss → theme}/components/_modal.scss +0 -0
  520. /package/{scss → theme}/components/_nav.scss +0 -0
  521. /package/{scss → theme}/components/_page-header.scss +0 -0
  522. /package/{scss → theme}/components/_popover.scss +0 -0
  523. /package/{scss → theme}/components/_progress.scss +0 -0
  524. /package/{scss → theme}/components/_prose.scss +0 -0
  525. /package/{scss → theme}/components/_scrollbar.scss +0 -0
  526. /package/{scss → theme}/components/_sections.scss +0 -0
  527. /package/{scss → theme}/components/_sidebar.scss +0 -0
  528. /package/{scss → theme}/components/_stat-card.scss +0 -0
  529. /package/{scss → theme}/components/_stepper.scss +0 -0
  530. /package/{scss → theme}/components/_timeline.scss +0 -0
  531. /package/{scss → theme}/components/_tooltip.scss +0 -0
  532. /package/{scss → theme}/components/_translations.scss +0 -0
  533. /package/{scss → theme}/config/_icons.scss +0 -0
  534. /package/{scss → theme}/config/_mixins.scss +0 -0
  535. /package/{scss → theme}/config/mixins/_ajax.scss +0 -0
  536. /package/{scss → theme}/config/mixins/_avatar.scss +0 -0
  537. /package/{scss → theme}/config/mixins/_breadcrumbs.scss +0 -0
  538. /package/{scss → theme}/config/mixins/_breakpoints.scss +0 -0
  539. /package/{scss → theme}/config/mixins/_chip.scss +0 -0
  540. /package/{scss → theme}/config/mixins/_circular-progress.scss +0 -0
  541. /package/{scss → theme}/config/mixins/_display.scss +0 -0
  542. /package/{scss → theme}/config/mixins/_empty-state.scss +0 -0
  543. /package/{scss → theme}/config/mixins/_focus.scss +0 -0
  544. /package/{scss → theme}/config/mixins/_interaction.scss +0 -0
  545. /package/{scss → theme}/config/mixins/_kbd.scss +0 -0
  546. /package/{scss → theme}/config/mixins/_link.scss +0 -0
  547. /package/{scss → theme}/config/mixins/_page-header.scss +0 -0
  548. /package/{scss → theme}/config/mixins/_position.scss +0 -0
  549. /package/{scss → theme}/config/mixins/_progress.scss +0 -0
  550. /package/{scss → theme}/config/mixins/_prose.scss +0 -0
  551. /package/{scss → theme}/config/mixins/_shadows.scss +0 -0
  552. /package/{scss → theme}/config/mixins/_sizing.scss +0 -0
  553. /package/{scss → theme}/config/mixins/_spacing.scss +0 -0
  554. /package/{scss → theme}/config/mixins/_stat-card.scss +0 -0
  555. /package/{scss → theme}/config/mixins/_stepper.scss +0 -0
  556. /package/{scss → theme}/config/mixins/_timeline.scss +0 -0
  557. /package/{scss → theme}/config/mixins/_transitions.scss +0 -0
  558. /package/{scss → theme}/config/mixins/_translations.scss +0 -0
  559. /package/{scss → theme}/tabler-icons.txt +0 -0
@@ -1,345 +1,403 @@
1
- import { registerComponent, dispatch, hashGet, hashSet, hashParse, hashLinkClick } from '../../ln-core';
2
-
3
- (function () {
4
- const DOM_SELECTOR = 'data-ln-modal-coordinator';
5
- const DOM_ATTRIBUTE = 'lnModalCoordinator';
6
-
7
- if (window[DOM_ATTRIBUTE] !== undefined) return;
8
-
9
- // Helper to resolve target modal from trigger element / wrapper / ID
10
- function _findTargetModal(triggerEl, modalId) {
11
- if (modalId) {
12
- if (triggerEl) {
13
- const wrapper = triggerEl.closest('[' + DOM_SELECTOR + ']');
14
- if (wrapper) {
15
- if (wrapper.id === modalId && wrapper.hasAttribute('data-ln-modal')) return wrapper;
16
- const scoped = wrapper.querySelector('#' + CSS.escape(modalId) + '[data-ln-modal], [data-ln-modal="' + modalId + '"]');
17
- if (scoped) return scoped;
18
- }
19
- }
20
- const el = document.getElementById(modalId) || document.querySelector('[data-ln-modal="' + modalId + '"]');
21
- if (el) return el;
22
- }
23
-
24
- if (triggerEl) {
25
- const wrapper = triggerEl.closest('[' + DOM_SELECTOR + ']');
26
- if (wrapper) {
27
- if (wrapper.hasAttribute('data-ln-modal')) return wrapper;
28
- const scoped = wrapper.querySelector('[data-ln-modal]');
29
- if (scoped) return scoped;
30
- }
31
- const closest = triggerEl.closest('[data-ln-modal]');
32
- if (closest) return closest;
33
- }
34
-
35
- return document.querySelector('[data-ln-modal]');
36
- }
37
-
38
- // Hash param for a modal open. Edit opens must carry a TRUTHY segment so
39
- // foreign hashchanges never route them through the empty-param reset branch
40
- // (which would wipe the edit fill). Prefer the real entity id
41
- // (data-ln-fill-id) for a bookmarkable URL; fall back to the non-addressable
42
- // marker 'edit' when the trigger fills inline with no id. New opens carry ''.
43
- function _hashParamForOpen(mode, triggerEl) {
44
- if (mode !== 'edit') return '';
45
- if (triggerEl) {
46
- const fillId = triggerEl.getAttribute('data-ln-fill-id');
47
- if (fillId) return fillId;
48
- }
49
- return 'edit';
50
- }
51
-
52
- // Helper to reset all forms and display fields inside a modal panel
53
- function _resetModalForm(modal) {
54
- if (!modal) return;
55
- const fields = modal.querySelectorAll('[data-ln-field]');
56
- for (let i = 0; i < fields.length; i++) {
57
- fields[i].textContent = '';
58
- }
59
- const forms = modal.querySelectorAll('form');
60
- for (let i = 0; i < forms.length; i++) {
61
- if (window.lnCore && typeof window.lnCore.lnFill === 'function') {
62
- window.lnCore.lnFill(forms[i], null);
63
- } else {
64
- forms[i].reset();
65
- }
66
- }
67
- }
68
-
69
- // ─── Native Submit Pending Intake & Hash Clear ───────────
70
-
71
- document.addEventListener('submit', function (e) {
72
- if (e.defaultPrevented) return;
73
- const form = e.target;
74
- const modal = form.closest('[data-ln-modal]');
75
- if (modal && modal.id) {
76
- try {
77
- sessionStorage.setItem('ln-modal-pending:' + modal.id, 'true');
78
- } catch (err) {}
79
- // Clear hash before native submit/reload so browser reloads clean
80
- hashSet(modal.id, null);
81
- }
82
- });
83
-
84
- // ─── Trigger & Hash Navigation Delegation ──────────────
85
-
86
- document.addEventListener('click', function (e) {
87
- if (e.ctrlKey || e.metaKey || e.button === 1) return;
88
-
89
- // 1. Handle trigger click [data-ln-modal-for="modalId"]
90
- const trigger = e.target.closest('[data-ln-modal-for]');
91
- if (trigger) {
92
- const modalId = trigger.getAttribute('data-ln-modal-for');
93
- const target = _findTargetModal(trigger, modalId);
94
- if (target && target.lnModal) {
95
- e.preventDefault();
96
-
97
- const MODAL_RESERVED = { lnModalFor: true, lnModalClose: true, lnModalMode: true };
98
- const record = {};
99
- const ds = trigger.dataset;
100
- for (const key in ds) {
101
- if (!key.startsWith('lnModal')) continue;
102
- if (MODAL_RESERVED[key]) continue;
103
- const suffix = key.slice(7);
104
- if (!suffix) continue;
105
- record[suffix.charAt(0).toLowerCase() + suffix.slice(1)] = ds[key];
106
- }
107
-
108
- const hasRecord = Object.keys(record).length > 0;
109
-
110
- if (trigger.hasAttribute('data-ln-modal-mode')) {
111
- target.dataset.lnModalMode = trigger.getAttribute('data-ln-modal-mode');
112
- } else {
113
- target.dataset.lnModalMode = hasRecord ? 'edit' : 'new';
114
- }
115
-
116
- if (hasRecord && window.lnCore && typeof window.lnCore.fill === 'function') {
117
- window.lnCore.fill(target, record);
118
- } else if (target.dataset.lnModalMode === 'new') {
119
- _resetModalForm(target);
120
- }
121
-
122
- const current = target.getAttribute('data-ln-modal');
123
- if (current === 'open') {
124
- dispatch(target, 'ln-modal:request-close', {});
125
- } else {
126
- // Restore per-open hash-write (pre-extraction invariant): every
127
- // open leaves a URL segment so _syncHashModals never closes it.
128
- if (target.id) {
129
- hashSet(target.id, _hashParamForOpen(target.dataset.lnModalMode, trigger));
130
- }
131
- dispatch(target, 'ln-modal:request-open', {});
132
- }
133
- }
134
- return;
135
- }
136
-
137
- // 2. Handle hash anchor click <a href="#modalId"> / <a href="#modalId:param">
138
- const hashAnchor = e.target.closest('a[href^="#"]');
139
- if (hashAnchor) {
140
- const map = hashParse(hashAnchor.getAttribute('href'));
141
- for (const ns in map) {
142
- const el = document.getElementById(ns);
143
- if (el && el.lnModal) {
144
- if (!hashLinkClick(e)) return;
145
- hashSet(ns, map[ns]);
146
- return;
147
- }
148
- }
149
- }
150
- });
151
-
152
- // ─── Before Open Reset Gate ────────────────────────────
153
-
154
- document.addEventListener('ln-modal:before-open', function (e) {
155
- const modal = e.target;
156
- if (!modal || !modal.lnModal) return;
157
-
158
- const mode = modal.dataset.lnModalMode || 'new';
159
- if (mode === 'new') {
160
- _resetModalForm(modal);
161
- }
162
- });
163
-
164
- // ─── Open Event Fill Dispatcher ───────────────────────
165
-
166
- document.addEventListener('ln-modal:open', function (e) {
167
- const modal = e.target;
168
- if (!modal || !modal.lnModal || !modal.id) return;
169
-
170
- let param = hashGet(modal.id);
171
-
172
- // Non-trigger opens (programmatic / SSR-via-mutation) reach here with no
173
- // segment — adopt one so foreign hashchanges never close the modal.
174
- // Trigger opens already wrote their segment, so this is skipped for them.
175
- if (param === null) {
176
- param = _hashParamForOpen(modal.dataset.lnModalMode, null);
177
- hashSet(modal.id, param);
178
- }
179
-
180
- if (param) {
181
- modal.dataset.lnModalMode = 'edit';
182
- modal.dispatchEvent(new CustomEvent('ln-fill:request', {
183
- bubbles: true,
184
- detail: { id: param }
185
- }));
186
- } else {
187
- modal.dataset.lnModalMode = 'new';
188
- _resetModalForm(modal);
189
- }
190
- });
191
-
192
- // ─── Hash Sync Listener & Pending Submit Resolution ────
193
-
194
- let _inSync = false;
195
- function _syncHashModals() {
196
- if (_inSync) return;
197
- _inSync = true;
198
- try {
199
- const modals = document.querySelectorAll('[data-ln-modal][id]');
200
- for (let i = 0; i < modals.length; i++) {
201
- const modal = modals[i];
202
- if (!modal.lnModal) continue;
203
- const hashNs = modal.id;
204
-
205
- const pendingKey = 'ln-modal-pending:' + hashNs;
206
- let isPending = false;
207
- try {
208
- isPending = sessionStorage.getItem(pendingKey) === 'true';
209
- } catch (err) {}
210
-
211
- if (isPending) {
212
- try {
213
- sessionStorage.removeItem(pendingKey);
214
- } catch (err) {}
215
-
216
- const hasErrors = !!(
217
- document.querySelector('.has-error, [data-ln-validate-error], .form-error, .alert-danger') ||
218
- modal.querySelector('.has-error, [data-ln-validate-error], .form-error, .alert-danger')
219
- );
220
-
221
- if (!hasErrors) {
222
- hashSet(hashNs, null);
223
- dispatch(modal, 'ln-modal:request-close', {});
224
- _resetModalForm(modal);
225
- continue;
226
- } else {
227
- modal.dataset.lnModalMode = 'edit';
228
- dispatch(modal, 'ln-modal:request-open', {});
229
- continue;
230
- }
231
- }
232
-
233
- const param = hashGet(hashNs);
234
- const present = param !== null;
235
- const isOpen = modal.lnModal.isOpen;
236
-
237
- if (present) {
238
- const mode = param ? 'edit' : 'new';
239
- modal.dataset.lnModalMode = mode;
240
- if (!isOpen) {
241
- dispatch(modal, 'ln-modal:request-open', {});
242
- } else {
243
- // Modal is already open, but hash param changed dynamically (e.g. #modal:42 -> #modal:5)
244
- if (param) {
245
- modal.dispatchEvent(new CustomEvent('ln-fill:request', {
246
- bubbles: true,
247
- detail: { id: param }
248
- }));
249
- } else {
250
- _resetModalForm(modal);
251
- }
252
- }
253
- } else if (isOpen) {
254
- dispatch(modal, 'ln-modal:request-close', {});
255
- }
256
- }
257
- } finally {
258
- _inSync = false;
259
- }
260
- }
261
-
262
- // SSR modals authored data-ln-modal="open" never pass through a trigger or
263
- // hash anchor, so they carry no URL segment. Adopt them into the hash BEFORE
264
- // the first sync, so _syncHashModals sees them present and keeps them open
265
- // instead of closing them as a phantom back-navigation. Skips modals that
266
- // already have a segment (e.g. an SSR deep-link URL).
267
- function _adoptOpenModals() {
268
- const openModals = document.querySelectorAll('[data-ln-modal="open"][id]');
269
- for (let i = 0; i < openModals.length; i++) {
270
- const modal = openModals[i];
271
- if (!modal.lnModal) continue;
272
- if (hashGet(modal.id) !== null) continue;
273
- hashSet(modal.id, _hashParamForOpen(modal.dataset.lnModalMode, null));
274
- }
275
- }
276
-
277
- window.addEventListener('hashchange', _syncHashModals);
278
-
279
- function _bootSync() {
280
- _adoptOpenModals();
281
- _syncHashModals();
282
- }
283
-
284
- if (document.readyState === 'loading') {
285
- document.addEventListener('DOMContentLoaded', function () {
286
- setTimeout(_bootSync, 0);
287
- });
288
- } else {
289
- setTimeout(_bootSync, 0);
290
- }
291
-
292
- // ─── Form Submission Auto-Close Mediation ────────────────
293
-
294
- function _handleFormSuccess(e) {
295
- const modal = e.target.closest('[data-ln-modal]');
296
- if (!modal || !modal.lnModal) return;
297
-
298
- if (modal.id) {
299
- try {
300
- sessionStorage.removeItem('ln-modal-pending:' + modal.id);
301
- } catch (err) {}
302
- hashSet(modal.id, null);
303
- }
304
-
305
- dispatch(modal, 'ln-modal:request-close', {});
306
- _resetModalForm(modal);
307
- }
308
-
309
- document.addEventListener('ln-form:success', _handleFormSuccess);
310
- document.addEventListener('ln-ajax:success', _handleFormSuccess);
311
-
312
- // ─── Hash Cleanup & Reset on Modal Close ───────────────
313
-
314
- document.addEventListener('ln-modal:close', function (e) {
315
- const modal = e.target;
316
- if (!modal || !modal.lnModal) return;
317
-
318
- if (modal.id) {
319
- try {
320
- sessionStorage.removeItem('ln-modal-pending:' + modal.id);
321
- } catch (err) {}
322
- if (hashGet(modal.id) !== null) {
323
- hashSet(modal.id, null);
324
- }
325
- }
326
-
327
- if (modal.dataset.lnModalMode === 'new') {
328
- _resetModalForm(modal);
329
- }
330
- });
331
-
332
- // ─── Component Constructor & Registration ────────────
333
-
334
- function _component(dom) {
335
- this.dom = dom;
336
- return this;
337
- }
338
-
339
- _component.prototype.destroy = function () {
340
- if (!this.dom[DOM_ATTRIBUTE]) return;
341
- delete this.dom[DOM_ATTRIBUTE];
342
- };
343
-
344
- registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-modal-coordinator');
345
- })();
1
+ import { registerComponent, dispatch, hashGet, hashSet, hashParse, hashLinkClick, queueBoot, buildDict } from '../../ln-core';
2
+
3
+ (function () {
4
+ const DOM_SELECTOR = 'data-ln-ui-coordinator';
5
+ const DOM_ATTRIBUTE = 'lnUiCoordinator';
6
+ const DICT_SELECTOR = 'data-ln-ui-coordinator-dict';
7
+
8
+ if (window[DOM_ATTRIBUTE] !== undefined) return;
9
+
10
+ // ─── Attribute Contract (SSOT) ──────────────────────────
11
+ const ATTRIBUTES = {
12
+ 'data-ln-ui-coordinator': { type: 'marker', description: 'Mounts UI coordinator mediating global hash-routing, modals, and toasts' },
13
+ 'data-ln-ui-coordinator-dict': { type: 'string', description: 'Dictionary key prefix mapping for translatable UI coordinator messages' }
14
+ };
15
+
16
+ // Resolve the active coordinator dictionary for a given event target.
17
+ // Climbs the DOM hierarchy of UI coordinators and merges dictionary keys from
18
+ // root to leaf so nested coordinators inherit and selectively override outer translations.
19
+ function _getCoordinatorDict(target) {
20
+ const dict = {};
21
+ let current = target;
22
+ const hosts = [];
23
+
24
+ while (current) {
25
+ const host = current.closest('[' + DOM_SELECTOR + ']');
26
+ if (!host) break;
27
+ if (host[DOM_ATTRIBUTE] && host[DOM_ATTRIBUTE].dict) {
28
+ hosts.unshift(host[DOM_ATTRIBUTE].dict);
29
+ }
30
+ current = host.parentElement;
31
+ }
32
+
33
+ for (const hDict of hosts) {
34
+ Object.assign(dict, hDict);
35
+ }
36
+
37
+ return dict;
38
+ }
39
+
40
+ // Helper to resolve target modal from trigger element / wrapper / ID
41
+ function _findTargetModal(triggerEl, modalId) {
42
+ if (modalId) {
43
+ if (triggerEl) {
44
+ const wrapper = triggerEl.closest('[' + DOM_SELECTOR + ']');
45
+ if (wrapper) {
46
+ if (wrapper.id === modalId && wrapper.hasAttribute('data-ln-modal')) return wrapper;
47
+ const scoped = wrapper.querySelector('#' + CSS.escape(modalId) + '[data-ln-modal], [data-ln-modal="' + modalId + '"]');
48
+ if (scoped) return scoped;
49
+ }
50
+ }
51
+ const el = document.getElementById(modalId) || document.querySelector('[data-ln-modal="' + modalId + '"]');
52
+ if (el) return el;
53
+ }
54
+
55
+ if (triggerEl) {
56
+ const wrapper = triggerEl.closest('[' + DOM_SELECTOR + ']');
57
+ if (wrapper) {
58
+ if (wrapper.hasAttribute('data-ln-modal')) return wrapper;
59
+ const scoped = wrapper.querySelector('[data-ln-modal]');
60
+ if (scoped) return scoped;
61
+ }
62
+ const closest = triggerEl.closest('[data-ln-modal]');
63
+ if (closest) return closest;
64
+ }
65
+
66
+ return document.querySelector('[data-ln-modal]');
67
+ }
68
+
69
+ // Hash param for a modal open. Edit opens must carry a TRUTHY segment so
70
+ // foreign hashchanges never route them through the empty-param reset branch
71
+ // (which would wipe the edit fill). Prefer the real entity id
72
+ // (data-ln-fill-id) for a bookmarkable URL; fall back to the non-addressable
73
+ // marker 'edit' when the trigger fills inline with no id. New opens carry ''.
74
+ function _hashParamForOpen(mode, triggerEl) {
75
+ if (mode !== 'edit') return '';
76
+ if (triggerEl) {
77
+ const fillId = triggerEl.getAttribute('data-ln-fill-id');
78
+ if (fillId) return fillId;
79
+ }
80
+ return 'edit';
81
+ }
82
+
83
+ // Helper to reset all forms and display fields inside a modal panel
84
+ function _resetModalForm(modal) {
85
+ if (!modal) return;
86
+ const fields = modal.querySelectorAll('[data-ln-field]');
87
+ for (let i = 0; i < fields.length; i++) {
88
+ fields[i].textContent = '';
89
+ }
90
+ const forms = modal.querySelectorAll('form');
91
+ for (let i = 0; i < forms.length; i++) {
92
+ if (window.lnCore && typeof window.lnCore.lnFill === 'function') {
93
+ window.lnCore.lnFill(forms[i], null);
94
+ } else {
95
+ forms[i].reset();
96
+ }
97
+ }
98
+ }
99
+
100
+ // ─── Trigger & Hash Navigation Delegation ──────────────
101
+
102
+ document.addEventListener('click', function (e) {
103
+ if (e.ctrlKey || e.metaKey || e.button === 1) return;
104
+
105
+ // 1. Handle trigger click [data-ln-modal-for="modalId"]
106
+ const trigger = e.target.closest('[data-ln-modal-for]');
107
+ if (trigger) {
108
+ const modalId = trigger.getAttribute('data-ln-modal-for');
109
+ const target = _findTargetModal(trigger, modalId);
110
+ if (target && target.lnModal) {
111
+ e.preventDefault();
112
+
113
+ const MODAL_RESERVED = { lnModalFor: true, lnModalClose: true, lnModalMode: true };
114
+ const record = {};
115
+ const ds = trigger.dataset;
116
+ for (const key in ds) {
117
+ if (!key.startsWith('lnModal')) continue;
118
+ if (MODAL_RESERVED[key]) continue;
119
+ const suffix = key.slice(7);
120
+ if (!suffix) continue;
121
+ record[suffix.charAt(0).toLowerCase() + suffix.slice(1)] = ds[key];
122
+ }
123
+
124
+ const hasRecord = Object.keys(record).length > 0;
125
+
126
+ if (trigger.hasAttribute('data-ln-modal-mode')) {
127
+ target.dataset.lnModalMode = trigger.getAttribute('data-ln-modal-mode');
128
+ } else {
129
+ target.dataset.lnModalMode = hasRecord ? 'edit' : 'new';
130
+ }
131
+
132
+ if (hasRecord && window.lnCore && typeof window.lnCore.lnFill === 'function') {
133
+ window.lnCore.lnFill(target, record);
134
+ } else if (target.dataset.lnModalMode === 'new') {
135
+ _resetModalForm(target);
136
+ }
137
+
138
+ const current = target.getAttribute('data-ln-modal');
139
+ if (current === 'open') {
140
+ dispatch(target, 'ln-modal:request-close', {});
141
+ } else {
142
+ // Restore per-open hash-write (pre-extraction invariant): every
143
+ // open leaves a URL segment so _syncHashModals never closes it.
144
+ if (target.id) {
145
+ hashSet(target.id, _hashParamForOpen(target.dataset.lnModalMode, trigger));
146
+ }
147
+ dispatch(target, 'ln-modal:request-open', {});
148
+ }
149
+ }
150
+ return;
151
+ }
152
+
153
+ // 2. Handle hash anchor click <a href="#modalId"> / <a href="#modalId:param">
154
+ const hashAnchor = e.target.closest('a[href^="#"]');
155
+ if (hashAnchor) {
156
+ const map = hashParse(hashAnchor.getAttribute('href'));
157
+ for (const ns in map) {
158
+ const el = document.getElementById(ns);
159
+ if (el && el.lnModal) {
160
+ if (!hashLinkClick(e)) return;
161
+ hashSet(ns, map[ns]);
162
+ return;
163
+ }
164
+ }
165
+ }
166
+ });
167
+
168
+ // ─── Before Open Reset Gate ────────────────────────────
169
+
170
+ document.addEventListener('ln-modal:before-open', function (e) {
171
+ const modal = e.target;
172
+ if (!modal || !modal.lnModal) return;
173
+
174
+ const mode = modal.dataset.lnModalMode || 'new';
175
+ if (mode === 'new') {
176
+ _resetModalForm(modal);
177
+ }
178
+ });
179
+
180
+ // ─── Open Event Fill Dispatcher ───────────────────────
181
+
182
+ document.addEventListener('ln-modal:open', function (e) {
183
+ const modal = e.target;
184
+ if (!modal || !modal.lnModal || !modal.id) return;
185
+
186
+ let param = hashGet(modal.id);
187
+
188
+ // Non-trigger opens (programmatic / SSR-via-mutation) reach here with no
189
+ // segment — adopt one so foreign hashchanges never close the modal.
190
+ // Trigger opens already wrote their segment, so this is skipped for them.
191
+ if (param === null) {
192
+ param = _hashParamForOpen(modal.dataset.lnModalMode, null);
193
+ hashSet(modal.id, param);
194
+ }
195
+
196
+ if (param) {
197
+ modal.dataset.lnModalMode = 'edit';
198
+ dispatch(modal, 'ln-fill:request', { id: param });
199
+ } else {
200
+ modal.dataset.lnModalMode = 'new';
201
+ _resetModalForm(modal);
202
+ }
203
+ });
204
+
205
+ // ─── Hash Sync Listener & Modal Route State ────────────
206
+
207
+ let _inSync = false;
208
+ function _syncHashModals() {
209
+ if (_inSync) return;
210
+ _inSync = true;
211
+ try {
212
+ const modals = document.querySelectorAll('[data-ln-modal][id]');
213
+ for (let i = 0; i < modals.length; i++) {
214
+ const modal = modals[i];
215
+ if (!modal.lnModal) continue;
216
+ const hashNs = modal.id;
217
+
218
+ const param = hashGet(hashNs);
219
+ const present = param !== null;
220
+ const isOpen = modal.lnModal.isOpen;
221
+
222
+ if (present) {
223
+ const mode = param ? 'edit' : 'new';
224
+ modal.dataset.lnModalMode = mode;
225
+ if (!isOpen) {
226
+ dispatch(modal, 'ln-modal:request-open', {});
227
+ } else {
228
+ // Modal is already open, but hash param changed dynamically (e.g. #modal:42 -> #modal:5)
229
+ if (param) {
230
+ dispatch(modal, 'ln-fill:request', { id: param });
231
+ } else {
232
+ _resetModalForm(modal);
233
+ }
234
+ }
235
+ } else if (isOpen) {
236
+ dispatch(modal, 'ln-modal:request-close', {});
237
+ }
238
+ }
239
+ } finally {
240
+ _inSync = false;
241
+ }
242
+ }
243
+
244
+ // SSR modals authored data-ln-modal="open" never pass through a trigger or
245
+ // hash anchor, so they carry no URL segment. Adopt them into the hash BEFORE
246
+ // the first sync, so _syncHashModals sees them present and keeps them open
247
+ // instead of closing them as a phantom back-navigation. Skips modals that
248
+ // already have a segment (e.g. an SSR deep-link URL).
249
+ function _adoptOpenModals() {
250
+ const openModals = document.querySelectorAll('[data-ln-modal="open"][id]');
251
+ for (let i = 0; i < openModals.length; i++) {
252
+ const modal = openModals[i];
253
+ if (!modal.lnModal) continue;
254
+ if (hashGet(modal.id) !== null) continue;
255
+ hashSet(modal.id, _hashParamForOpen(modal.dataset.lnModalMode, null));
256
+ }
257
+ }
258
+
259
+ window.addEventListener('hashchange', _syncHashModals);
260
+
261
+ function _bootSync() {
262
+ _adoptOpenModals();
263
+ _syncHashModals();
264
+ }
265
+
266
+ if (document.readyState === 'loading') {
267
+ document.addEventListener('DOMContentLoaded', function () {
268
+ queueBoot(_bootSync);
269
+ });
270
+ } else {
271
+ queueBoot(_bootSync);
272
+ }
273
+
274
+ // ─── AJAX Submission Mediation & Toast Routing ──────────
275
+
276
+ function _handleAjaxSuccess(e) {
277
+ const detail = e.detail || {};
278
+ const data = detail.data;
279
+
280
+ // 1. Dispatch UI toast notification if response envelope contains a message
281
+ if (data && data.message) {
282
+ const msg = data.message;
283
+ dispatch(window, 'ln-toast:enqueue', {
284
+ type: msg.type || 'success',
285
+ title: msg.title || '',
286
+ message: msg.body || ''
287
+ });
288
+ }
289
+
290
+ // 2. Auto-close modal and clean up if the submitting element was inside a modal
291
+ const modal = e.target.closest('[data-ln-modal]');
292
+ if (modal && modal.lnModal) {
293
+ if (modal.id) {
294
+ hashSet(modal.id, null);
295
+ }
296
+
297
+ dispatch(modal, 'ln-modal:request-close', {});
298
+ _resetModalForm(modal);
299
+ }
300
+ }
301
+
302
+ function _handleAjaxError(e) {
303
+ const detail = e.detail || {};
304
+ const data = detail.data;
305
+ const status = detail.status || 0;
306
+ const dict = _getCoordinatorDict(e.target);
307
+
308
+ // 1. If server returned structured error message, toast it
309
+ if (data && data.message) {
310
+ const msg = data.message;
311
+ dispatch(window, 'ln-toast:enqueue', {
312
+ type: msg.type || 'error',
313
+ title: msg.title || '',
314
+ message: msg.body || ''
315
+ });
316
+ } else if (status === 0) {
317
+ // 2. Genuine network failure (DNS / offline / abort / connection dropped)
318
+ dispatch(window, 'ln-toast:enqueue', {
319
+ type: 'error',
320
+ title: dict['network-error-title'] || '',
321
+ message: dict['network-error'] || 'Network error'
322
+ });
323
+ } else {
324
+ // 3. Server HTTP error (status >= 400 or HTML error page) without structured JSON message
325
+ dispatch(window, 'ln-toast:enqueue', {
326
+ type: 'error',
327
+ title: dict['server-error-title'] || '',
328
+ message: dict['server-error'] || 'Server error'
329
+ });
330
+ }
331
+
332
+ // Note: We deliberately do NOT close the modal on error so form validation feedback remains visible
333
+ }
334
+
335
+ document.addEventListener('ln-ajax:success', _handleAjaxSuccess);
336
+ document.addEventListener('ln-ajax:error', _handleAjaxError);
337
+
338
+ // ─── Upload Feedback Mediation ──────────────────────────
339
+
340
+ function _handleUploadInvalid(e) {
341
+ const detail = e.detail || {};
342
+ const dict = _getCoordinatorDict(e.target);
343
+ const message = detail.message || (detail.reason === 'max-size' ? dict['upload-max-size'] || 'File is too large' : (detail.reason === 'max-files' ? dict['upload-max-files'] || 'Maximum file count exceeded' : dict['upload-invalid-type'] || 'This file type is not allowed'));
344
+ const title = dict['upload-invalid-title'] || 'Invalid File';
345
+
346
+ dispatch(window, 'ln-toast:enqueue', {
347
+ type: 'error',
348
+ title: title,
349
+ message: message
350
+ });
351
+ }
352
+
353
+ function _handleUploadError(e) {
354
+ const detail = e.detail || {};
355
+ const dict = _getCoordinatorDict(e.target);
356
+ const message = detail.message || dict['upload-failed'] || 'Failed to upload file';
357
+ const title = dict['upload-error-title'] || 'Upload Error';
358
+
359
+ dispatch(window, 'ln-toast:enqueue', {
360
+ type: 'error',
361
+ title: title,
362
+ message: message
363
+ });
364
+ }
365
+
366
+ document.addEventListener('ln-upload:invalid', _handleUploadInvalid);
367
+ document.addEventListener('ln-upload:error', _handleUploadError);
368
+
369
+ // ─── Hash Cleanup & Reset on Modal Close ───────────────
370
+
371
+ document.addEventListener('ln-modal:close', function (e) {
372
+ const modal = e.target;
373
+ if (!modal || !modal.lnModal) return;
374
+
375
+ if (modal.id) {
376
+ if (hashGet(modal.id) !== null) {
377
+ hashSet(modal.id, null);
378
+ }
379
+ }
380
+
381
+ if (modal.dataset.lnModalMode === 'new') {
382
+ _resetModalForm(modal);
383
+ }
384
+ });
385
+
386
+ // ─── Component Constructor & Registration ────────────
387
+
388
+ function _component(dom) {
389
+ this.dom = dom;
390
+ this.dict = buildDict(dom, DICT_SELECTOR);
391
+ return this;
392
+ }
393
+
394
+ _component.prototype.destroy = function () {
395
+ if (!this.dom[DOM_ATTRIBUTE]) return;
396
+ this.dict = {};
397
+ delete this.dom[DOM_ATTRIBUTE];
398
+ };
399
+
400
+ registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-ui-coordinator', {
401
+ attributes: ATTRIBUTES
402
+ });
403
+ })();