@livenetworks/ashlar 1.6.0 → 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 (560) 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/components/ln-confirm/README.md +216 -0
  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 -167
  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/README.md +0 -162
  414. package/js/ln-confirm/_ln-confirm.scss +0 -24
  415. package/js/ln-confirm/ln-confirm.js +0 -1
  416. package/js/ln-core/crypto.js +0 -83
  417. package/js/ln-core/helpers.js +0 -788
  418. package/js/ln-core/index.js +0 -7
  419. package/js/ln-core/persist.js +0 -97
  420. package/js/ln-couchdb-connector/ln-couchdb-connector.js +0 -1
  421. package/js/ln-data-coordinator/ln-data-coordinator.js +0 -1
  422. package/js/ln-data-coordinator/src/data-read-policy.js +0 -18
  423. package/js/ln-data-store/ln-data-store.js +0 -1
  424. package/js/ln-date/ln-date.js +0 -1
  425. package/js/ln-date/src/ln-date.js +0 -603
  426. package/js/ln-debug/README.md +0 -58
  427. package/js/ln-debug/ln-debug.js +0 -1
  428. package/js/ln-debug/src/ln-debug.js +0 -19
  429. package/js/ln-dropdown/ln-dropdown.js +0 -1
  430. package/js/ln-dropdown/ln-dropdown.scss +0 -15
  431. package/js/ln-editor/ln-editor.js +0 -1
  432. package/js/ln-editor/ln-editor.scss +0 -43
  433. package/js/ln-external-links/ln-external-links.js +0 -1
  434. package/js/ln-fill/ln-fill.js +0 -1
  435. package/js/ln-filter/README.md +0 -189
  436. package/js/ln-filter/ln-filter-dev.scss +0 -8
  437. package/js/ln-filter/ln-filter.js +0 -1
  438. package/js/ln-filter/src/ln-filter.js +0 -419
  439. package/js/ln-form/ln-form.js +0 -1
  440. package/js/ln-http/ln-http.js +0 -1
  441. package/js/ln-link/ln-link.js +0 -1
  442. package/js/ln-list/README.md +0 -129
  443. package/js/ln-list/ln-list.js +0 -1
  444. package/js/ln-list/ln-list.scss +0 -28
  445. package/js/ln-modal/ln-modal-dev.scss +0 -13
  446. package/js/ln-modal/ln-modal.js +0 -1
  447. package/js/ln-modal/ln-modal.scss +0 -35
  448. package/js/ln-modal-coordinator/README.md +0 -99
  449. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +0 -8
  450. package/js/ln-modal-coordinator/ln-modal-coordinator.js +0 -1
  451. package/js/ln-nav/ln-nav.js +0 -1
  452. package/js/ln-number/README.md +0 -149
  453. package/js/ln-number/ln-number.js +0 -1
  454. package/js/ln-number/src/ln-number.js +0 -443
  455. package/js/ln-options/ln-options.js +0 -1
  456. package/js/ln-popover/ln-popover.js +0 -1
  457. package/js/ln-progress/ln-progress.js +0 -1
  458. package/js/ln-progress/src/ln-progress.js +0 -98
  459. package/js/ln-router/ln-router.js +0 -1
  460. package/js/ln-search/README.md +0 -158
  461. package/js/ln-search/ln-search-dev.scss +0 -8
  462. package/js/ln-search/ln-search.js +0 -1
  463. package/js/ln-search/src/ln-search.js +0 -117
  464. package/js/ln-slug/ln-slug.js +0 -1
  465. package/js/ln-sort/ln-sort.js +0 -1
  466. package/js/ln-sort/src/ln-sort.js +0 -178
  467. package/js/ln-sortable/ln-sortable.js +0 -1
  468. package/js/ln-stat/ln-stat.js +0 -1
  469. package/js/ln-table/ln-table.js +0 -1
  470. package/js/ln-table/ln-table.scss +0 -11
  471. package/js/ln-table-coordinator/README.md +0 -73
  472. package/js/ln-table-coordinator/ln-table-coordinator.js +0 -1
  473. package/js/ln-table-coordinator/src/ln-table-coordinator.js +0 -160
  474. package/js/ln-tabs/ln-tabs-dev.scss +0 -18
  475. package/js/ln-tabs/ln-tabs.js +0 -1
  476. package/js/ln-tabs/src/ln-tabs.js +0 -188
  477. package/js/ln-time/ln-time.js +0 -1
  478. package/js/ln-toast/ln-toast.js +0 -1
  479. package/js/ln-toggle/ln-toggle.js +0 -1
  480. package/js/ln-tooltip/ln-tooltip.js +0 -1
  481. package/js/ln-tooltip/ln-tooltip.scss +0 -9
  482. package/js/ln-translations/ln-translations.js +0 -1
  483. package/js/ln-upload/README.md +0 -255
  484. package/js/ln-upload/ln-upload.js +0 -1
  485. package/js/ln-upload/ln-upload.scss +0 -20
  486. package/js/ln-upload/src/ln-upload.js +0 -423
  487. package/js/ln-validate/ln-validate.js +0 -1
  488. package/scss/components/_button.scss +0 -20
  489. package/scss/components/_confirm.scss +0 -5
  490. package/scss/components/_form.scss +0 -107
  491. package/scss/components/_status-badge.scss +0 -4
  492. package/scss/components/_toast.scss +0 -68
  493. package/scss/components/_upload.scss +0 -51
  494. package/scss/config/_theme.scss +0 -216
  495. package/scss/config/mixins/_btn.scss +0 -179
  496. package/scss/config/mixins/_confirm.scss +0 -31
  497. package/scss/config/mixins/_dropdown.scss +0 -141
  498. package/scss/config/mixins/_popover.scss +0 -64
  499. package/scss/ln-ashlar-dev.scss +0 -39
  500. /package/{js → components}/ln-core/positioning.js +0 -0
  501. /package/{js → components}/ln-core/reactive.js +0 -0
  502. /package/{js → components}/ln-filter/ln-filter.scss +0 -0
  503. /package/{js → components}/ln-icon/ln-icon.js +0 -0
  504. /package/{js → components}/ln-icon/src/ln-icon.js +0 -0
  505. /package/{js → components}/ln-search/ln-search.scss +0 -0
  506. /package/{js → components}/ln-toast/template.html +0 -0
  507. /package/{scss → theme}/components/_accordion.scss +0 -0
  508. /package/{scss → theme}/components/_ajax.scss +0 -0
  509. /package/{scss → theme}/components/_alert.scss +0 -0
  510. /package/{scss → theme}/components/_avatar.scss +0 -0
  511. /package/{scss → theme}/components/_breadcrumbs.scss +0 -0
  512. /package/{scss → theme}/components/_card.scss +0 -0
  513. /package/{scss → theme}/components/_chip.scss +0 -0
  514. /package/{scss → theme}/components/_circular-progress.scss +0 -0
  515. /package/{scss → theme}/components/_editor.scss +0 -0
  516. /package/{scss → theme}/components/_empty-state.scss +0 -0
  517. /package/{scss → theme}/components/_filter.scss +0 -0
  518. /package/{scss → theme}/components/_link.scss +0 -0
  519. /package/{scss → theme}/components/_loader.scss +0 -0
  520. /package/{scss → theme}/components/_modal.scss +0 -0
  521. /package/{scss → theme}/components/_nav.scss +0 -0
  522. /package/{scss → theme}/components/_page-header.scss +0 -0
  523. /package/{scss → theme}/components/_popover.scss +0 -0
  524. /package/{scss → theme}/components/_progress.scss +0 -0
  525. /package/{scss → theme}/components/_prose.scss +0 -0
  526. /package/{scss → theme}/components/_scrollbar.scss +0 -0
  527. /package/{scss → theme}/components/_sections.scss +0 -0
  528. /package/{scss → theme}/components/_sidebar.scss +0 -0
  529. /package/{scss → theme}/components/_stat-card.scss +0 -0
  530. /package/{scss → theme}/components/_stepper.scss +0 -0
  531. /package/{scss → theme}/components/_timeline.scss +0 -0
  532. /package/{scss → theme}/components/_tooltip.scss +0 -0
  533. /package/{scss → theme}/components/_translations.scss +0 -0
  534. /package/{scss → theme}/config/_icons.scss +0 -0
  535. /package/{scss → theme}/config/_mixins.scss +0 -0
  536. /package/{scss → theme}/config/mixins/_ajax.scss +0 -0
  537. /package/{scss → theme}/config/mixins/_avatar.scss +0 -0
  538. /package/{scss → theme}/config/mixins/_breadcrumbs.scss +0 -0
  539. /package/{scss → theme}/config/mixins/_breakpoints.scss +0 -0
  540. /package/{scss → theme}/config/mixins/_chip.scss +0 -0
  541. /package/{scss → theme}/config/mixins/_circular-progress.scss +0 -0
  542. /package/{scss → theme}/config/mixins/_display.scss +0 -0
  543. /package/{scss → theme}/config/mixins/_empty-state.scss +0 -0
  544. /package/{scss → theme}/config/mixins/_focus.scss +0 -0
  545. /package/{scss → theme}/config/mixins/_interaction.scss +0 -0
  546. /package/{scss → theme}/config/mixins/_kbd.scss +0 -0
  547. /package/{scss → theme}/config/mixins/_link.scss +0 -0
  548. /package/{scss → theme}/config/mixins/_page-header.scss +0 -0
  549. /package/{scss → theme}/config/mixins/_position.scss +0 -0
  550. /package/{scss → theme}/config/mixins/_progress.scss +0 -0
  551. /package/{scss → theme}/config/mixins/_prose.scss +0 -0
  552. /package/{scss → theme}/config/mixins/_shadows.scss +0 -0
  553. /package/{scss → theme}/config/mixins/_sizing.scss +0 -0
  554. /package/{scss → theme}/config/mixins/_spacing.scss +0 -0
  555. /package/{scss → theme}/config/mixins/_stat-card.scss +0 -0
  556. /package/{scss → theme}/config/mixins/_stepper.scss +0 -0
  557. /package/{scss → theme}/config/mixins/_timeline.scss +0 -0
  558. /package/{scss → theme}/config/mixins/_transitions.scss +0 -0
  559. /package/{scss → theme}/config/mixins/_translations.scss +0 -0
  560. /package/{scss → theme}/tabler-icons.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  import { dispatch, registerComponent } from '../../ln-core';
2
+ import { hasInitialValue, isFieldValid, resolveActiveErrorKeys } from './validate-model.js';
2
3
 
3
4
  (function () {
4
5
  const DOM_SELECTOR = 'data-ln-validate';
@@ -8,18 +9,15 @@ import { dispatch, registerComponent } from '../../ln-core';
8
9
  const CSS_VALID = 'ln-validate-valid';
9
10
  const CSS_INVALID = 'ln-validate-invalid';
10
11
 
11
- const ERROR_MAP = {
12
- required: 'valueMissing',
13
- typeMismatch: 'typeMismatch',
14
- tooShort: 'tooShort',
15
- tooLong: 'tooLong',
16
- patternMismatch: 'patternMismatch',
17
- rangeUnderflow: 'rangeUnderflow',
18
- rangeOverflow: 'rangeOverflow'
19
- };
20
-
21
12
  if (window[DOM_ATTRIBUTE] !== undefined) return;
22
13
 
14
+ // ─── Attribute Contract (SSOT) ──────────────────────────
15
+ const ATTRIBUTES = {
16
+ 'data-ln-validate': { type: 'marker', description: 'Activates validation on form input or field' },
17
+ 'data-ln-validate-errors': { type: 'marker', description: 'Container element holding validation error message elements' },
18
+ 'data-ln-validate-error': { type: 'string', description: 'Identifies error message template for a specific validation rule' }
19
+ };
20
+
23
21
  // ─── Component ─────────────────────────────────────────────
24
22
 
25
23
  function _component(dom) {
@@ -67,7 +65,6 @@ import { dispatch, registerComponent } from '../../ln-core';
67
65
  if (el) el.classList.add('hidden');
68
66
  }
69
67
  } else {
70
- // clear all custom errors
71
68
  self._customErrors.forEach(function (err) {
72
69
  if (parent) {
73
70
  const el = parent.querySelector('[' + ERROR_SELECTOR + '="' + err + '"]');
@@ -76,7 +73,6 @@ import { dispatch, registerComponent } from '../../ln-core';
76
73
  });
77
74
  self._customErrors.clear();
78
75
  }
79
- // Re-run native validation to update visual state
80
76
  if (self._touched) self.validate();
81
77
  };
82
78
 
@@ -89,8 +85,6 @@ import { dispatch, registerComponent } from '../../ln-core';
89
85
 
90
86
  const form = dom.form;
91
87
  if (form) {
92
- // One validated field is enough to own the form's gate —
93
- // browser bubbles must yield to ln-validate's own error display.
94
88
  if (!form.hasAttribute('novalidate')) {
95
89
  form.setAttribute('novalidate', '');
96
90
  }
@@ -108,16 +102,6 @@ import { dispatch, registerComponent } from '../../ln-core';
108
102
  form.addEventListener('reset', this._onFormReset);
109
103
  form.addEventListener('ln-validate:request-validate', this._onValidateRequest);
110
104
 
111
- // Submit gate — attached once per form, by whichever validated
112
- // field initializes first (marker lives on the form itself,
113
- // same one-shot-guard shape as ln-fill's _fillBound). Runs on
114
- // every method, GET included — this is a straight replacement
115
- // for the native browser validation `novalidate` just silenced
116
- // above, and native validation never had a method condition
117
- // either. ln-data-coordinator's own POST/PUT/PATCH method gate
118
- // for the write pipeline is a separate, later decision — it
119
- // reads e.defaultPrevented first, so it never claims a submit
120
- // this gate already blocked.
121
105
  if (!form._lnValidateGateBound) {
122
106
  form._lnValidateGateBound = true;
123
107
  form.addEventListener('submit', function (e) {
@@ -131,23 +115,24 @@ import { dispatch, registerComponent } from '../../ln-core';
131
115
  });
132
116
  validationDetail.invalidFields[0].focus();
133
117
  }
134
- // Valid — nothing left to do. Native submit continues;
135
- // ln-data-coordinator (document, bubble phase) or plain
136
- // HTML/ln-ajax decides what happens to it next.
137
118
  });
138
119
  }
139
120
  }
140
121
 
122
+ if (hasInitialValue(dom)) {
123
+ this._touched = true;
124
+ this.validate();
125
+ }
126
+
141
127
  return this;
142
128
  }
143
129
 
144
130
  _component.prototype.validate = function () {
145
131
  const dom = this.dom;
146
132
  const validity = dom.validity;
147
- const nativeValid = dom.checkValidity();
148
- const isValid = nativeValid && this._customErrors.size === 0;
133
+ const isValid = isFieldValid(validity, this._customErrors.size);
134
+ const activeErrors = resolveActiveErrorKeys(validity, this._customErrors);
149
135
 
150
- // Show/hide error messages
151
136
  const parent = dom.closest('.form-element');
152
137
  if (parent) {
153
138
  const errorList = parent.querySelector('[' + ERRORS_SELECTOR + ']');
@@ -155,27 +140,17 @@ import { dispatch, registerComponent } from '../../ln-core';
155
140
  const items = errorList.querySelectorAll('[' + ERROR_SELECTOR + ']');
156
141
  for (let i = 0; i < items.length; i++) {
157
142
  const errorKey = items[i].getAttribute(ERROR_SELECTOR);
158
- const validityProp = ERROR_MAP[errorKey];
159
- if (!validityProp) continue; // custom error — managed by set-custom/clear-custom
160
- if (validity[validityProp]) {
161
- items[i].classList.remove('hidden');
162
- } else {
163
- items[i].classList.add('hidden');
164
- }
143
+ items[i].classList.toggle('hidden', !activeErrors.includes(errorKey));
165
144
  }
166
145
  }
167
146
  }
168
147
 
169
- // Toggle CSS classes on input
170
148
  dom.classList.toggle(CSS_VALID, isValid);
171
149
  dom.classList.toggle(CSS_INVALID, !isValid);
172
-
173
- // Manage ARIA invalid attribute
174
150
  dom.setAttribute('aria-invalid', isValid ? 'false' : 'true');
175
151
 
176
- // Emit event
177
152
  const eventName = isValid ? 'ln-validate:valid' : 'ln-validate:invalid';
178
- dispatch(dom, eventName, { target: dom, field: dom.name });
153
+ dispatch(dom, eventName, { target: dom, field: dom.name, errors: activeErrors });
179
154
 
180
155
  return isValid;
181
156
  };
@@ -196,7 +171,9 @@ import { dispatch, registerComponent } from '../../ln-core';
196
171
  };
197
172
 
198
173
  Object.defineProperty(_component.prototype, 'isValid', {
199
- get: function () { return this.dom.checkValidity() && this._customErrors.size === 0; }
174
+ get: function () {
175
+ return isFieldValid(this.dom.validity, this._customErrors.size);
176
+ }
200
177
  });
201
178
 
202
179
  _component.prototype.destroy = function () {
@@ -214,11 +191,12 @@ import { dispatch, registerComponent } from '../../ln-core';
214
191
 
215
192
  this.dom.classList.remove(CSS_VALID, CSS_INVALID);
216
193
  this.dom.removeAttribute('aria-invalid');
217
- dispatch(this.dom, 'ln-validate:destroyed', { target: this.dom });
218
194
  delete this.dom[DOM_ATTRIBUTE];
219
195
  };
220
196
 
221
197
  // ─── Init ──────────────────────────────────────────────────
222
198
 
223
- registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-validate');
199
+ registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-validate', {
200
+ attributes: ATTRIBUTES
201
+ });
224
202
  })();
@@ -0,0 +1,64 @@
1
+ export const ERROR_MAP = {
2
+ required: 'valueMissing',
3
+ typeMismatch: 'typeMismatch',
4
+ tooShort: 'tooShort',
5
+ tooLong: 'tooLong',
6
+ patternMismatch: 'patternMismatch',
7
+ rangeUnderflow: 'rangeUnderflow',
8
+ rangeOverflow: 'rangeOverflow'
9
+ };
10
+
11
+ /**
12
+ * Checks if a field is valid given its native validity state and custom errors count.
13
+ * @param {{ valid?: boolean } | null | undefined} validityState
14
+ * @param {number} [customErrorsCount=0]
15
+ * @returns {boolean}
16
+ */
17
+ export function isFieldValid(validityState, customErrorsCount = 0) {
18
+ if (!validityState) return customErrorsCount === 0;
19
+ return Boolean(validityState.valid && customErrorsCount === 0);
20
+ }
21
+
22
+ /**
23
+ * Whether a field already holds a value at init, so it is validated up front.
24
+ * A checkbox or radio always carries a `value` ("on" by default) — only its
25
+ * `checked` state says whether anything was chosen.
26
+ * @param {{ type?: string, value?: string, checked?: boolean }} field
27
+ * @returns {boolean}
28
+ */
29
+ export function hasInitialValue(field) {
30
+ if (field.type === 'checkbox' || field.type === 'radio') return Boolean(field.checked);
31
+ return Boolean(field.value && field.value.trim() !== '');
32
+ }
33
+
34
+ /**
35
+ * Resolves all active error keys for a given validity state and custom errors set.
36
+ * @param {Record<string, boolean>} validityState
37
+ * @param {Set<string>|Array<string>} [customErrors]
38
+ * @returns {string[]}
39
+ */
40
+ export function resolveActiveErrorKeys(validityState, customErrors) {
41
+ const active = [];
42
+
43
+ if (validityState) {
44
+ const keys = Object.keys(ERROR_MAP);
45
+ for (let i = 0; i < keys.length; i++) {
46
+ const errorKey = keys[i];
47
+ const prop = ERROR_MAP[errorKey];
48
+ if (validityState[prop]) {
49
+ active.push(errorKey);
50
+ }
51
+ }
52
+ }
53
+
54
+ if (customErrors) {
55
+ const customList = Array.from(customErrors);
56
+ for (let i = 0; i < customList.length; i++) {
57
+ if (customList[i] && active.indexOf(customList[i]) === -1) {
58
+ active.push(customList[i]);
59
+ }
60
+ }
61
+ }
62
+
63
+ return active;
64
+ }
@@ -0,0 +1,166 @@
1
+ # `data-ln-websocket-connector`
2
+
3
+ > Applied to an element inside a `ln-data-coordinator`. Opens a WebSocket, turns server pushes into
4
+ > `ln-websocket-connector:fetched`, and answers the same request events as `ln-api-connector` and
5
+ > `ln-couchdb-connector`. Connection status is private state announced by events — never an attribute.
6
+
7
+ A zero-dependency push transport. Beside a REST connector it only delivers live changes; on its own
8
+ it carries reads, writes and pushes over one socket.
9
+
10
+ ---
11
+
12
+ ## Declarative DOM Setup
13
+
14
+ ### Live changes beside REST
15
+
16
+ The REST connector takes every request; the socket only pushes changes into the store.
17
+
18
+ ```html
19
+ <ul data-ln-data-coordinator="tasks" hidden>
20
+ <li data-ln-data-store="tasks" id="tasks"></li>
21
+ <li data-ln-api-connector data-ln-api-base-url="https://api.example.com" data-ln-api-path="tasks"></li>
22
+ <li data-ln-websocket-connector data-ln-websocket-connector-url="wss://api.example.com/live"></li>
23
+ </ul>
24
+ ```
25
+
26
+ ### Socket alone
27
+
28
+ With no REST or CouchDB connector in the coordinator, the socket takes every request too.
29
+
30
+ ```html
31
+ <ul data-ln-data-coordinator="tasks" hidden>
32
+ <li data-ln-data-store="tasks" id="tasks"></li>
33
+ <li data-ln-websocket-connector data-ln-websocket-connector-url="wss://api.example.com/live"></li>
34
+ </ul>
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Attributes
40
+
41
+ Both attributes are commands set from outside; the component obeys them.
42
+
43
+ | Attribute | Values | Default | Description |
44
+ |-----------|--------|---------|-------------|
45
+ | `data-ln-websocket-connector` | `connect` \| `disconnect` | `connect` | Opens or closes the socket. A bare attribute connects. |
46
+ | `data-ln-websocket-connector-url` | `ws://…` \| `wss://…` | — | Endpoint. Changing it while connected closes and reopens on the new URL. |
47
+
48
+ There is no attribute for the connection status. `connecting`, `connected` and `disconnected` are
49
+ what the component observes, not something anyone can set — writing `connected` into an attribute
50
+ would not connect anything. The status is announced by events; whoever listens decides how to show it.
51
+
52
+ ---
53
+
54
+ ## DOM Events
55
+
56
+ ### Commands (dispatched TO the connector)
57
+
58
+ Only the `ln-websocket-connector:*` namespace is handled.
59
+
60
+ | Event | `detail` | Description |
61
+ |-------|----------|-------------|
62
+ | `ln-websocket-connector:request-sync` | `{ since, meta? }` | Delta sync since a token. |
63
+ | `ln-websocket-connector:request-query` | `{ query, meta? }` | One page of a query (`search`, `filters`, `sort`, `offset`, `limit`). |
64
+ | `ln-websocket-connector:request-create` | `{ data, tempId?, idempotencyKey?, meta? }` | Create a record. |
65
+ | `ln-websocket-connector:request-update` | `{ id, data, expected_version?, idempotencyKey?, meta? }` | Update a record. |
66
+ | `ln-websocket-connector:request-delete` | `{ id, idempotencyKey?, meta? }` | Delete a record. |
67
+ | `ln-websocket-connector:request-bulk-delete` | `{ ids, idempotencyKey?, meta? }` | Delete several records. |
68
+
69
+ ### Notifications (emitted BY the connector)
70
+
71
+ | Event | `detail` | Description |
72
+ |-------|----------|-------------|
73
+ | `ln-websocket-connector:connecting` | `{ url, attempt }` | A connection attempt starts. `attempt` counts from 1 and resets on open. |
74
+ | `ln-websocket-connector:connected` | `{ url }` | The socket is open. |
75
+ | `ln-websocket-connector:disconnected` | `{ url, code, reason, willReconnect }` | The socket closed, or a pending reconnect was cancelled. |
76
+ | `ln-websocket-connector:fetched` | `{ data, since, meta }` / `{ data, total, filtered, offset, queryGen, meta }` | A sync reply, a query page, or a server push (`meta: null`). |
77
+ | `ln-websocket-connector:created` | `{ record, tempId, message, meta }` | Create confirmed. |
78
+ | `ln-websocket-connector:updated` | `{ record, id, message, meta }` | Update confirmed. |
79
+ | `ln-websocket-connector:deleted` | `{ response, id, message, meta }` | Delete confirmed. |
80
+ | `ln-websocket-connector:bulk-deleted` | `{ response, ids, message, meta }` | Bulk delete confirmed. |
81
+ | `ln-websocket-connector:error` | `{ action, error, status, data, conflictData, meta, … }` | A rejected request, or one that could not be delivered (`status: 0`). |
82
+
83
+ `meta` is echoed unchanged and never leaves the page.
84
+
85
+ ---
86
+
87
+ ## Wire Protocol
88
+
89
+ JSON text frames.
90
+
91
+ **Request** — `{ "ref": "<string>", "type": "<type>", ...payload }`
92
+
93
+ | `type` | payload |
94
+ |--------|---------|
95
+ | `sync` | `since` |
96
+ | `query` | `query` |
97
+ | `create` | `data`, `idempotencyKey` |
98
+ | `update` | `id`, `data`, `expected_version`, `idempotencyKey` |
99
+ | `delete` | `id`, `idempotencyKey` |
100
+ | `bulk-delete` | `ids`, `idempotencyKey` |
101
+
102
+ **Reply** — the same `ref`, then either `{ "ok": true, "content": …, "message": … }` or
103
+ `{ "ok": false, "status": 409, "error": "…", "data": … }`. `content` is `{ data, deleted, synced_at }`
104
+ for `sync`, `{ data, total, filtered }` for `query`, the record for `create` / `update`, and the
105
+ server response for `delete` / `bulk-delete`. `message` is the same opaque toast payload as the REST
106
+ `{ message, content }` envelope.
107
+
108
+ **Push** — no `ref`: `{ "type": "changes", "data": [...], "deleted": [...], "synced_at": … }`.
109
+
110
+ `synced_at` is the same token the REST delta takes as `since`. Beside REST, a push advances the
111
+ store's `lastSyncedAt`, and the next REST sync sends it — the server must keep both in one currency.
112
+
113
+ ---
114
+
115
+ ## Coordinator Integration
116
+
117
+ `ln-data-coordinator` needs no wiring:
118
+
119
+ - **Request connector:** `[data-ln-api-connector]` or `[data-ln-couchdb-connector]` when present,
120
+ otherwise `[data-ln-websocket-connector]`.
121
+ - **Pushes:** `:fetched` without `meta.kind` goes to `store.applySync` — upsert plus delete, the path
122
+ CouchDB sync already uses. Bound tables and lists refresh on `ln-data-store:synced`.
123
+ - **Catch-up:** on every `:connected` the coordinator runs `store.forceSync()`, a delta since
124
+ `lastSyncedAt`, over whichever connector takes requests.
125
+
126
+ ### Showing the status
127
+
128
+ The coordinator does not render connection status. Page wiring listens and draws it — here with
129
+ an app-owned `data-status`, since app state stays out of `data-ln-*`:
130
+
131
+ ```js
132
+ const chip = document.getElementById('tasks-status');
133
+ ['connecting', 'connected', 'disconnected'].forEach(function (status) {
134
+ coordinatorEl.addEventListener('ln-websocket-connector:' + status, function () {
135
+ chip.setAttribute('data-status', status);
136
+ });
137
+ });
138
+ ```
139
+
140
+ ---
141
+
142
+ ## 🔧 Internals
143
+
144
+ Source: `components/ln-websocket-connector/src/ln-websocket-connector.js`.
145
+
146
+ ### Requests while not connected
147
+
148
+ - **Command `connect`, socket not open** (first connect, or between reconnect attempts): the request
149
+ is held and sent in order on open. `:connected` is dispatched before the flush, so the coordinator's
150
+ catch-up sync sees the store already syncing and does not send a second one.
151
+ - **Command `disconnect`:** the request fails at once with `:error { status: 0 }`.
152
+ - **Socket closes with replies outstanding:** each one fails with `:error { status: 0 }`. The
153
+ coordinator treats status 0 as transient and never deletes local data on it.
154
+
155
+ ### Reconnect
156
+
157
+ An unexpected close while the command is `connect` retries after 1 s, doubling up to 30 s, and the
158
+ counter resets on a successful open. `new WebSocket()` throwing synchronously (an invalid URL, or
159
+ `ws://` blocked on an `https://` page) is not retried: retrying cannot fix it. The component reports
160
+ `:disconnected { willReconnect: false }`; a new URL or a new `connect` command opens again.
161
+
162
+ ### Teardown
163
+
164
+ `destroy()` closes the socket, clears the reconnect timer, removes the request listeners and
165
+ deletes the instance. It dispatches nothing, so held and outstanding requests are discarded, not
166
+ failed.
@@ -0,0 +1 @@
1
+ (function(){"use strict";function I(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function k(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){o=t[r];break}if(!k(o))return}e.apply(console,t)}}function b(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function 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()}const $={};function H(e,t){$[e]=t}function U(e){return $[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=H,window.lnCore.getDataMapper=U);function J(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,C(function(){new MutationObserver(function(){b(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const N={};function P(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];N[n]=t}function Q(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return N[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=P,window.lnCore.getLocaleFallback=Q,window.lnCore.ensureLocaleObserver=J);const A={};function G(e,t){A[e]||(A[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=A[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function D(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++){const a=n[l],d=a.getAttribute("data-ln-field");t[d]!=null&&(a.textContent=t[d])}const o=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<o.length;l++){const a=o[l],d=a.getAttribute("data-ln-attr").split(",");for(let h=0;h<d.length;h++){const u=d[h].trim().split(":");if(u.length!==2)continue;const i=u[0].trim(),c=u[1].trim();t[c]!=null&&a.setAttribute(i,t[c])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const a=r[l],d=a.getAttribute("data-ln-show");d in t&&a.classList.toggle("hidden",!t[d])}const s=e.querySelectorAll("[data-ln-class]");for(let l=0;l<s.length;l++){const a=s[l],d=a.getAttribute("data-ln-class").split(",");for(let h=0;h<d.length;h++){const u=d[h].trim().split(":");if(u.length!==2)continue;const i=u[0].trim(),c=u[1].trim();c in t&&a.classList.toggle(i,!!t[c])}}return e}function X(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)D(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 M(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const s=n.currentNode;s.textContent.indexOf("{{")!==-1&&(s.textContent=s.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,a){return t[a]!==void 0?t[a]:""}))}const o=function(s,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let s=0;s<r.length;s++){const l=r[s],a=l.attributes;for(let d=0;d<a.length;d++){const h=a[d];h.value.indexOf("{{")!==-1&&l.setAttribute(h.name,h.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function z(e,t,n,o,r,s){const l={};for(let d=0;d<e.children.length;d++){const h=e.children[d],u=h.getAttribute("data-ln-render-key");u&&(l[u]=h)}const a=document.createDocumentFragment();for(let d=0;d<t.length;d++){const h=t[d],u=String(o(h));let i=l[u];if(i)r(i,h,d);else{const c=G(n,s);if(!c||(M(c,h),i=c.firstElementChild,!i))continue;i.setAttribute("data-ln-render-key",u),r(i,h,d)}a.appendChild(i)}e.textContent="",e.appendChild(a)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=M,window.lnCore.fill=D,window.lnCore.lnFill=X,window.lnCore.renderList=z);function v(e,t,n){const o=e.getAttribute(t);return o===null?n:o}function Y(e,t,n){const o=parseInt(e.getAttribute(t),10);return isNaN(o)?n:o}function Z(e,t,n=!1){const o=e.getAttribute(t);if(o===null)return!!n;const r=o.trim().toLowerCase();return!(r==="false"||r==="0")}function ee(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const S=new Map;function te(e,t){const n=(e?e.join("|"):"")+"::"+t;if(S.has(n))return S.get(n);const o=new Set(e||[]),r=function(s,l){const a=s.getAttribute(l);return a!==null&&o.has(a)?a:t};return S.set(n,r),r}function ne(e,t,n){const o=parseFloat(e.getAttribute(t));return isNaN(o)?n:o}function oe(e,t,n){const o=e.getAttribute(t);if(!o)return n;try{return JSON.parse(o)}catch{return n}}function F(e,t,n,o,r){if(!e||t===null)return!0;const s=o||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const a=d=>{r?console.warn(d,r):console.warn(d)};if(l==="boolean"){const d=t.trim().toLowerCase();return d!==""&&d!=="true"&&d!=="false"&&d!=="1"&&d!=="0"?(a(`[${s}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const d=e.values||[];return d.includes(t)?!0:(a(`[${s}] Invalid value "${t}" for attribute "${n}". Allowed: ${d.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return a(`[${s}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const d=parseInt(t,10);return e.min!==void 0&&d<e.min?(a(`[${s}] Value ${d} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&d>e.max?(a(`[${s}] Value ${d} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(a(`[${s}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(d){return a(`[${s}] Invalid JSON for attribute "${n}": ${d.message}. Fallback: ${e.fallback}.`),!1}return!0}function re(e,t,n){for(const o in n){const[r,s,l]=n[o];Object.defineProperty(e,o,{get:function(){return r(t,s,l)},enumerable:!0,configurable:!0})}return e}function ie(e){const t={};for(const n in e){const o=e[n];if(!o||!o.prop)continue;let r=o.read;if(!r&&o.type)switch(o.type){case"enum":r=te(o.values,o.fallback);break;case"integer":r=Y;break;case"float":r=ne;break;case"boolean":r=Z;break;case"list":r=ee;break;case"json":r=oe;break;case"string":default:r=v;break}r||(r=v),t[o.prop]=[r,n,o.fallback]}return t}function se(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function le(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function O(e,t,n,o){if(e.nodeType!==1)return;const s=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l=Array.from(e.querySelectorAll(s));e.matches&&e.matches(s)&&l.push(e);for(const a of l)if(!a[n]){window.lnCore._persistSink&&a.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(a,t);try{a[n]=new o(a)}catch(d){console.error("["+n+"] init failed",a,d)}}}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 de(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 B(){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 ae(e){const t=B(),n=e.observed||[];for(let o=0;o<n.length;o++){const r=n[o];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const r=t.byDeclaredAttr.get(o);r.some(s=>s.componentTag===e.componentTag)||r.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=le(e);if(o===null)t.reactiveWildcard.push(e);else for(const r of o)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function W(e,t,n,o){for(let r=0;r<e.length;r++){const s=e[r];if(!t[s.attribute])continue;const l=s.effects&&s.effects[n];l?l(t,n,o):s.onAttrChange&&(!s.declared||s.declared.has(n))&&s.onAttrChange(t,n,o)}}function ue(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=B(),r=o.byAttr.get(n);if(I()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&k(t)){const s=o.byDeclaredAttr.get(n),l=t.getAttribute(n);for(let a=0;a<s.length;a++)F(s[a].spec,l,n,s[a].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||r)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const s=o.byReactive.get(n);s&&W(s,t,n,e.oldValue),o.reactiveWildcard.length&&W(o.reactiveWildcard,t,n,e.oldValue)}if(r)for(let s=0;s<r.length;s++){const l=r[s];if(l.handler){l.handler(t,n,e.oldValue);continue}l.onAttributeChange&&t[l.attribute]?l.onAttributeChange(t,n):(O(t,l.selector,l.attribute,l.ComponentFn),l.onInit&&l.onInit(t))}}function fe(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,C(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{ue(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function j(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function he(e){const t=j();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const r=o.query,s=e.target.nodeType===1?e.target.matches(r)?e.target:e.target.closest(r):e.target.parentElement?e.target.parentElement.closest(r):null;s&&o.onSubtreeChange(s,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const s=t[r];O(o,s.selector,s.attribute,s.ComponentFn),s.onInit&&s.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const s=t[r],l=s.query,a=Array.from(o.querySelectorAll(l));o.matches&&o.matches(l)&&a.push(o);for(let d=0;d<a.length;d++){const h=a[d];if(!document.contains(h)){const u=h[s.attribute];if(u&&typeof u.destroy=="function")try{u.destroy()}catch(i){console.error("["+s.attribute+"] destroy failed",h,i)}delete h[s.attribute]}}}}}}function we(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,C(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{he(o)}catch(r){console.error("[ln-core] lifecycle handler failed",o.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function pe(e,t,n,o,r={}){const s=r.extraAttributes||[],l=r.onAttributeChange||null,a=r.onSubtreeChange||null,d=r.onInit||null,h=r.onAttrChange||null,u=r.effects||null,i=r.attributes||null,c=i?se(i):u,f=i?new Set(Object.keys(i)):null,p=r.persist||null;function w(x){const m=x||document.body;if(O(m,e,t,n),i&&I())for(const _ in i){const ve=i[_],R=Array.from(m.querySelectorAll("["+_+"]"));m.matches&&m.matches("["+_+"]")&&R.push(m);for(let T=0;T<R.length;T++){const L=R[T];k(L)&&F(ve,L.getAttribute(_),_,o,L)}}d&&d(m)}const g=[];if(e.indexOf("[")!==-1){const x=/\[([\w-]+)/g;let m;for(;(m=x.exec(e))!==null;)g.push(m[1])}else g.push(e);ae({selector:e,attribute:t,componentTag:o,attributes:i,ComponentFn:n,onInit:d,observed:g.concat(s),onAttributeChange:l,onAttrChange:h,effects:c,declared:f,persist:p}),fe();const y=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";j().push({selector:e,attribute:t,ComponentFn:n,onInit:d,onSubtreeChange:a,query:y}),we(),window[t]=w;function V(){ce()>0?de(function(){w(document.body)}):w(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",V):V(),w}function K(e){return(e||"").replace(/^#/,"")}function q(e){const t=e===void 0?location.hash:e,n={},o=K(t);if(!o)return n;const r=o.split("&");for(let s=0;s<r.length;s++){const l=r[s];if(!l)continue;const a=l.indexOf(":"),d=a>-1?l.slice(0,a):l,h=a>-1?l.slice(a+1):"";if(d)try{n[d]=decodeURIComponent(h)}catch{n[d]=h}}return n}function be(e){if(!e)return null;const t=q();return e in t?t[e]:null}function ge(e,t){if(!e)return;const n=q();t==null?delete n[e]:n[e]=String(t);const r=Object.keys(n).map(function(s){const l=n[s];return l===""?s:s+":"+encodeURIComponent(l)}).join("&");K(location.hash)!==r&&(location.hash=r)}function me(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function ye(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function _e(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Ce(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 ke(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Ae(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),r=o?o.split(",").map(function(s){try{return decodeURIComponent(s)}catch{return s}}).filter(Boolean):[];return{key:n,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=q,window.lnCore.hashGet=be,window.lnCore.hashSet=ge,window.lnCore.hashLinkClick=me,window.lnCore.resolveHashNamespace=ye,window.lnCore.hashSortEncode=_e,window.lnCore.hashSortDecode=Ce,window.lnCore.hashFilterEncode=ke,window.lnCore.hashFilterDecode=Ae),(function(){const e="data-ln-websocket-connector",t="lnWebsocketConnector";if(window[t]!==void 0)return;const n=1e3,o=3e4;function r(i){const c=i[t];c&&(c.command==="connect"?c._open():c._disconnect())}function s(i){const c=i[t];!c||c.command!=="connect"||(c._drop("url-changed"),c._open())}const l={"data-ln-websocket-connector":{prop:"command",type:"enum",values:["connect","disconnect"],fallback:"connect",effect:r,description:"Connection command set from outside: connect or disconnect"},"data-ln-websocket-connector-url":{prop:"url",read:v,type:"string",fallback:"",effect:s,description:"WebSocket endpoint URL (ws:// or wss://)"}},a=ie(l),d={"ln-websocket-connector:request-sync":"sync","ln-websocket-connector:request-query":"query","ln-websocket-connector:request-create":"create","ln-websocket-connector:request-update":"update","ln-websocket-connector:request-delete":"delete","ln-websocket-connector:request-bulk-delete":"bulk-delete"};function h(i,c){return i==="sync"?{since:c.since}:i==="query"?{query:c.query||{}}:i==="create"?{data:c.data,idempotencyKey:c.idempotencyKey}:i==="update"?{id:c.id,data:c.data,expected_version:c.expected_version,idempotencyKey:c.idempotencyKey}:i==="delete"?{id:c.id,idempotencyKey:c.idempotencyKey}:{ids:c.ids,idempotencyKey:c.idempotencyKey}}function u(i){this.dom=i,re(this,i,a),i[t]=this,this._socket=null,this._status="disconnected",this._attempt=0,this._timer=null,this._seq=0,this._pending=new Map,this._held=[];const c=this;this._onRequest=function(f){c._request(d[f.type],f.detail||{})};for(const f in d)i.addEventListener(f,this._onRequest);return this.command==="connect"&&this._open(),this}u.prototype._open=function(){if(this._socket||this._timer)return;const i=this,c=this.url;this._attempt++,this._status="connecting",b(this.dom,"ln-websocket-connector:connecting",{url:c,attempt:this._attempt});let f;try{f=new WebSocket(c)}catch(p){this._status="disconnected",this._attempt=0,this._failAll(this._held,p.message),this._held=[],b(this.dom,"ln-websocket-connector:disconnected",{url:c,code:0,reason:p.message,willReconnect:!1});return}this._socket=f,f.onopen=function(){i._status="connected",i._attempt=0,b(i.dom,"ln-websocket-connector:connected",{url:c});const p=i._held;i._held=[];for(let w=0;w<p.length;w++)i._send(p[w])},f.onmessage=function(p){i._receive(p.data)},f.onclose=function(p){i._socket=null,i._status="disconnected",i._failPending("connection closed");const w=i.command==="connect";b(i.dom,"ln-websocket-connector:disconnected",{url:c,code:p.code,reason:p.reason,willReconnect:w}),w&&i._scheduleReconnect()}},u.prototype._scheduleReconnect=function(){const i=this,c=Math.min(n*Math.pow(2,Math.max(0,this._attempt-1)),o);this._timer=setTimeout(function(){i._timer=null,i._open()},c)},u.prototype._drop=function(i){const c=!!(this._socket||this._timer);clearTimeout(this._timer),this._timer=null,this._attempt=0,this._socket&&(this._socket.onopen=this._socket.onmessage=this._socket.onclose=null,this._socket.close(1e3,i),this._socket=null),c&&(this._status="disconnected",this._failPending("connection closed"),b(this.dom,"ln-websocket-connector:disconnected",{url:this.url,code:1e3,reason:i,willReconnect:!1}))},u.prototype._disconnect=function(){this._drop("disconnect"),this._failAll(this._held,"disconnected"),this._held=[]},u.prototype._request=function(i,c){const f={ref:String(++this._seq),type:i,detail:c};this._status==="connected"?this._send(f):this.command==="connect"?this._held.push(f):this._fail(f,0,"disconnected",null)},u.prototype._send=function(i){this._pending.set(i.ref,i),this._socket.send(JSON.stringify(Object.assign({ref:i.ref,type:i.type},h(i.type,i.detail))))},u.prototype._receive=function(i){let c;try{c=JSON.parse(i)}catch{console.warn("[ln-websocket-connector] Ignored a frame that is not JSON:",i);return}if(c.ref!==void 0){const f=this._pending.get(String(c.ref));if(!f)return;this._pending.delete(f.ref),c.ok?this._resolve(f,c.content,c.message||null):this._fail(f,c.status||0,c.error,c.data);return}c.type==="changes"&&b(this.dom,"ln-websocket-connector:fetched",{data:{data:c.data||[],deleted:c.deleted||[],synced_at:c.synced_at},since:null,meta:null})},u.prototype._resolve=function(i,c,f){const p=i.detail,w=p.meta||null,g=this.dom;if(i.type==="sync")b(g,"ln-websocket-connector:fetched",{data:c,since:p.since,meta:w});else if(i.type==="query"){const E=p.query||{},y=c||{};b(g,"ln-websocket-connector:fetched",{data:y.data||[],total:y.total,filtered:y.filtered,offset:E.offset,queryGen:E.queryGen,meta:w})}else i.type==="create"?b(g,"ln-websocket-connector:created",{record:c,tempId:p.tempId,message:f,meta:w}):i.type==="update"?b(g,"ln-websocket-connector:updated",{record:c,id:p.id,message:f,meta:w}):i.type==="delete"?b(g,"ln-websocket-connector:deleted",{response:c,id:p.id,message:f,meta:w}):b(g,"ln-websocket-connector:bulk-deleted",{response:c,ids:p.ids,message:f,meta:w})},u.prototype._fail=function(i,c,f,p){const w=i.detail;b(this.dom,"ln-websocket-connector:error",{action:i.type,error:f,status:c,data:p||null,conflictData:c===409&&p||null,since:w.since,id:w.id,ids:w.ids,tempId:w.tempId,meta:w.meta||null})},u.prototype._failAll=function(i,c){for(let f=0;f<i.length;f++)this._fail(i[f],0,c,null)},u.prototype._failPending=function(i){const c=Array.from(this._pending.values());this._pending.clear(),this._failAll(c,i)},u.prototype.destroy=function(){if(this.dom[t]){for(const i in d)this.dom.removeEventListener(i,this._onRequest);clearTimeout(this._timer),this._timer=null,this._socket&&(this._socket.onopen=this._socket.onmessage=this._socket.onclose=null,this._socket.close(1e3,"destroy"),this._socket=null),this._pending.clear(),this._held=[],delete this.dom[t]}},pe(e,t,u,"ln-websocket-connector",{attributes:l})})()})();
@@ -0,0 +1,29 @@
1
+ {
2
+ "$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
3
+ "component": "ln-websocket-connector",
4
+ "generator": "scripts/sync-ln-schemas.mjs",
5
+ "attributes": {
6
+ "data-ln-websocket-connector": {
7
+ "direction": null,
8
+ "sources": [
9
+ "src/ln-websocket-connector.js"
10
+ ],
11
+ "type": "enum",
12
+ "values": [
13
+ "connect",
14
+ "disconnect"
15
+ ],
16
+ "fallback": "connect",
17
+ "description": "Connection command set from outside: connect or disconnect"
18
+ },
19
+ "data-ln-websocket-connector-url": {
20
+ "direction": null,
21
+ "sources": [
22
+ "src/ln-websocket-connector.js"
23
+ ],
24
+ "type": "string",
25
+ "fallback": "",
26
+ "description": "WebSocket endpoint URL (ws:// or wss://)"
27
+ }
28
+ }
29
+ }