@livenetworks/ashlar 1.6.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. package/LICENSE +641 -0
  2. package/README.md +190 -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,213 +1,247 @@
1
- // ─── Windowed Sparse Cache ─────────────────────────────────
2
- //
3
- // DOM-agnostic sliding-window data engine for server-side virtualization.
4
- // Owns a sparse cache keyed by logical index, logical/grand totals, request
5
- // dedup, a stale-guard via queryGen, LRU eviction to a bounded cap, and a
6
- // debounced fetch trigger. Transport-agnostic: the consumer supplies
7
- // requestPage() (kick a fetch — any transport) and onChange() (cache mutated,
8
- // re-render). Render clients pull rows via get()/has() and read logicalTotal
9
- // for spacer geometry; they hold no cache of their own. Shared by the ln-table
10
- // and ln-list windowed paths; a future ln-data-store windowed mode plugs in by
11
- // making requestPage resolve getAll({offset,limit}) then call ingest().
12
-
13
- export function createWindowCache(config) {
14
- config = config || {};
15
- let windowSize = config.windowSize > 0 ? config.windowSize : 1000;
16
- let pageSize = config.pageSize > 0 ? config.pageSize : 200;
17
- let threshold = config.threshold != null ? config.threshold : 25;
18
- let fetchDebounce = config.fetchDebounce != null ? config.fetchDebounce : 120;
19
- const requestPage = typeof config.requestPage === 'function' ? config.requestPage : function () {};
20
- const onChange = typeof config.onChange === 'function' ? config.onChange : function () {};
21
-
22
- const map = new Map(); // logicalIndex → record
23
- const touch = new Map(); // logicalIndex → seq (LRU stamp)
24
- const inflight = new Set(); // offsets currently requested (dedup)
25
- let logicalTotal = 0;
26
- let grandTotal = 0;
27
- let queryGen = 0;
28
- let query = { sort: null, filters: {}, search: '' };
29
- let debounceId = null;
30
- let seq = 0;
31
- let lastRangeStart = 0; // last ensure() visible range — revalidate() re-targets here, not page 0
32
- let lastRangeEnd = 0;
33
- let pendingSwap = false; // set by invalidate()/revalidate(), consumed by the new generation's first ingest()
34
-
35
- function stamp(i) { touch.set(i, ++seq); }
36
-
37
- function hasActiveQuery() {
38
- return !!(query && (query.search || (query.filters && Object.keys(query.filters).length)));
39
- }
40
-
41
- function evict() {
42
- if (map.size <= windowSize) return;
43
- // LRU: drop least-recently touched/requested rows first
44
- const keys = Array.from(map.keys()).sort(function (a, b) {
45
- return (touch.get(a) || 0) - (touch.get(b) || 0);
46
- });
47
- let i = 0;
48
- while (map.size > windowSize && i < keys.length) {
49
- map.delete(keys[i]);
50
- touch.delete(keys[i]);
51
- i++;
52
- }
53
- }
54
-
55
- function fire(offset, limit) {
56
- inflight.add(offset);
57
- requestPage(query, offset, limit);
58
- }
59
-
60
- return {
61
- get: function (i) { return map.get(i); },
62
- has: function (i) { return map.has(i); },
63
- peek: function () { return map.size ? map.values().next().value : undefined; },
64
-
65
- get logicalTotal() { return logicalTotal; },
66
- get grandTotal() { return grandTotal; },
67
- get queryGen() { return queryGen; },
68
- get size() { return map.size; },
69
-
70
- // Render client hands its visible logical range; stamps in-range resident
71
- // rows as freshly used, then checks if any page in range (padded by threshold)
72
- // is missing from cache and needs to be fetched (page-aligned).
73
- ensure: function (startRow, endRow) {
74
- clearTimeout(debounceId);
75
- lastRangeStart = startRow;
76
- lastRangeEnd = endRow;
77
- for (let i = startRow; i < endRow; i++) {
78
- if (map.has(i)) stamp(i);
79
- }
80
- if (logicalTotal <= 0) return;
81
-
82
- const checkStart = Math.max(0, startRow - threshold);
83
- const checkEnd = Math.min(logicalTotal, endRow + threshold);
84
-
85
- const firstPage = Math.floor(checkStart / pageSize);
86
- const lastPage = Math.floor(Math.max(0, checkEnd - 1) / pageSize);
87
-
88
- let targetPageOffset = -1;
89
- let targetPageLimit = pageSize;
90
-
91
- for (let p = firstPage; p <= lastPage; p++) {
92
- const pOffset = p * pageSize;
93
- const pLimit = Math.min(pageSize, logicalTotal - pOffset);
94
-
95
- let hasMissing = false;
96
- for (let i = pOffset; i < pOffset + pLimit; i++) {
97
- if (!map.has(i)) {
98
- hasMissing = true;
99
- break;
100
- }
101
- }
102
-
103
- if (hasMissing && !inflight.has(pOffset)) {
104
- targetPageOffset = pOffset;
105
- targetPageLimit = pLimit;
106
- break;
107
- }
108
- }
109
-
110
- if (targetPageOffset === -1) return;
111
-
112
- debounceId = setTimeout(function () {
113
- fire(targetPageOffset, targetPageLimit);
114
- }, fetchDebounce);
115
- },
116
-
117
- // Splice a fetched page. Stale (superseded-query) responses are dropped.
118
- // Out-of-order pages splice at their own offset, so order is irrelevant.
119
- ingest: function (detail) {
120
- detail = detail || {};
121
- if (detail.queryGen != null && detail.queryGen !== queryGen) return;
122
-
123
- // First response of a new generation: drop the stale rows now, at the
124
- // swap moment, not at invalidate()/revalidate() time — stale-while-revalidate.
125
- if (pendingSwap) {
126
- map.clear();
127
- touch.clear();
128
- pendingSwap = false;
129
- }
130
-
131
- grandTotal = detail.total != null ? detail.total : grandTotal;
132
- logicalTotal = detail.filtered != null
133
- ? detail.filtered
134
- : (detail.data ? detail.data.length : logicalTotal);
135
-
136
- const offset = detail.offset || 0;
137
- const rows = detail.data || [];
138
- for (let i = 0; i < rows.length; i++) {
139
- map.set(offset + i, rows[i]);
140
- stamp(offset + i);
141
- }
142
- inflight.delete(offset);
143
- evict();
144
- onChange();
145
- },
146
-
147
- // First load: fetch page 0 at the current generation (no bump).
148
- requestInitial: function (q) {
149
- if (q) query = q;
150
- fire(0, pageSize);
151
- },
152
-
153
- // Query change: new generation, stale rows stay visible until the first
154
- // response of the new generation lands in ingest() — no blanking, no
155
- // placeholder flash (ln-table--loading is the refresh affordance).
156
- invalidate: function (q) {
157
- queryGen++;
158
- inflight.clear();
159
- clearTimeout(debounceId);
160
- if (q) query = q;
161
- pendingSwap = true;
162
- fire(0, pageSize);
163
- },
164
-
165
- // Post-mutation refresh of a windowed view: same stale-while-revalidate
166
- // swap as invalidate(), but re-requests the page at the CURRENT scroll
167
- // position instead of jumping back to page 0.
168
- revalidate: function () {
169
- queryGen++;
170
- inflight.clear();
171
- clearTimeout(debounceId);
172
- pendingSwap = true;
173
- const offset = Math.max(0, Math.floor(lastRangeStart / pageSize) * pageSize);
174
- const limit = logicalTotal > 0 ? Math.min(pageSize, Math.max(1, logicalTotal - offset)) : pageSize;
175
- fire(offset, limit);
176
- },
177
-
178
- // Failed page fetch: release the offset so the next ensure() (scroll,
179
- // filter, resize) can re-request it. No onChange(), no auto-retry.
180
- release: function (offset) {
181
- inflight.delete(offset);
182
- },
183
-
184
- destroy: function () {
185
- clearTimeout(debounceId);
186
- map.clear();
187
- touch.clear();
188
- inflight.clear();
189
- },
190
-
191
- configure: function (partial) {
192
- partial = partial || {};
193
- let geometryChanged = false;
194
- if (partial.windowSize != null && partial.windowSize > 0 && partial.windowSize !== windowSize) {
195
- const shrank = partial.windowSize < windowSize;
196
- windowSize = partial.windowSize;
197
- if (shrank) evict();
198
- geometryChanged = true;
199
- }
200
- if (partial.pageSize != null && partial.pageSize > 0) pageSize = partial.pageSize;
201
- if (partial.threshold != null && partial.threshold >= 0) threshold = partial.threshold;
202
- if (partial.fetchDebounce != null && partial.fetchDebounce >= 0) fetchDebounce = partial.fetchDebounce;
203
- if (geometryChanged) onChange();
204
- },
205
-
206
- setGrandTotal: function (n) {
207
- if (n == null || isNaN(n) || n < 0) return;
208
- grandTotal = n;
209
- if (!hasActiveQuery()) logicalTotal = n;
210
- onChange();
211
- }
212
- };
213
- }
1
+ // ─── Windowed Sparse Cache ─────────────────────────────────
2
+ //
3
+ // DOM-agnostic sliding-window data engine for server-side virtualization.
4
+ // Owns a sparse cache keyed by logical index, logical/grand totals, request
5
+ // dedup, a stale-guard via queryGen, LRU eviction to a bounded cap, and a
6
+ // debounced fetch trigger. Transport-agnostic: the consumer supplies
7
+ // requestPage() (kick a fetch — any transport) and onChange() (cache mutated,
8
+ // re-render). Render clients pull rows via get()/has() and read logicalTotal
9
+ // for spacer geometry; they hold no cache of their own. Shared by the ln-table
10
+ // and ln-list windowed paths; a future ln-data-store windowed mode plugs in by
11
+ // making requestPage resolve getAll({offset,limit}) then call ingest().
12
+
13
+ export function createWindowCache(config) {
14
+ config = config || {};
15
+ let windowSize = config.windowSize > 0 ? config.windowSize : 1000;
16
+ let pageSize = config.pageSize > 0 ? config.pageSize : 200;
17
+ let threshold = config.threshold != null ? config.threshold : 25;
18
+ let fetchDebounce = config.fetchDebounce != null ? config.fetchDebounce : 120;
19
+ const requestPage = typeof config.requestPage === 'function' ? config.requestPage : function () {};
20
+ const onChange = typeof config.onChange === 'function' ? config.onChange : function () {};
21
+
22
+ const map = new Map(); // logicalIndex → record
23
+ const touch = new Map(); // logicalIndex → seq (LRU stamp)
24
+ const inflight = new Set(); // offsets currently requested (dedup)
25
+ let logicalTotal = 0;
26
+ let grandTotal = 0;
27
+ let queryGen = 0;
28
+ let query = { sort: null, filters: {}, search: '' };
29
+ let debounceId = null;
30
+ let seq = 0;
31
+ let lastRangeStart = 0; // last ensure() visible range — revalidate() re-targets here, not page 0
32
+ let lastRangeEnd = 0;
33
+ let pendingSwap = false; // set by invalidate()/revalidate(), consumed by the new generation's first ingest()
34
+
35
+ function stamp(i) { touch.set(i, ++seq); }
36
+
37
+ function hasActiveQuery() {
38
+ return !!(query && (query.search || (query.filters && Object.keys(query.filters).length)));
39
+ }
40
+
41
+ function evict() {
42
+ if (map.size <= windowSize) return;
43
+ // LRU: drop least-recently touched/requested rows first
44
+ const keys = Array.from(map.keys()).sort(function (a, b) {
45
+ return (touch.get(a) || 0) - (touch.get(b) || 0);
46
+ });
47
+ let i = 0;
48
+ while (map.size > windowSize && i < keys.length) {
49
+ map.delete(keys[i]);
50
+ touch.delete(keys[i]);
51
+ i++;
52
+ }
53
+ }
54
+
55
+ function fire(offset, limit) {
56
+ inflight.add(offset);
57
+ requestPage(query, offset, limit);
58
+ }
59
+
60
+ return {
61
+ get: function (i) { return map.get(i); },
62
+ has: function (i) { return map.has(i); },
63
+ peek: function () { return map.size ? map.values().next().value : undefined; },
64
+
65
+ get logicalTotal() { return logicalTotal; },
66
+ get grandTotal() { return grandTotal; },
67
+ get queryGen() { return queryGen; },
68
+ get size() { return map.size; },
69
+
70
+ // Render client hands its visible logical range; stamps in-range resident
71
+ // rows as freshly used, then checks if any page in range (padded by threshold)
72
+ // is missing from cache and needs to be fetched (page-aligned).
73
+ ensure: function (startRow, endRow) {
74
+ clearTimeout(debounceId);
75
+ lastRangeStart = startRow;
76
+ lastRangeEnd = endRow;
77
+ for (let i = startRow; i < endRow; i++) {
78
+ if (map.has(i)) stamp(i);
79
+ }
80
+ if (logicalTotal <= 0) return;
81
+
82
+ const checkStart = Math.max(0, startRow - threshold);
83
+ const checkEnd = Math.min(logicalTotal, endRow + threshold);
84
+
85
+ const firstPage = Math.floor(checkStart / pageSize);
86
+ const lastPage = Math.floor(Math.max(0, checkEnd - 1) / pageSize);
87
+
88
+ let targetPageOffset = -1;
89
+
90
+ for (let p = firstPage; p <= lastPage; p++) {
91
+ const pOffset = p * pageSize;
92
+ // Bounds the missing-row scan only — the request always asks for a
93
+ // full page. logicalTotal is a stale carry-over between invalidate()
94
+ // and the new generation's first ingest(); clamping the limit by it
95
+ // short-fetches the page and costs a second request for the same offset.
96
+ const pLimit = Math.min(pageSize, logicalTotal - pOffset);
97
+
98
+ let hasMissing = false;
99
+ const pageCheckStart = Math.max(pOffset, checkStart);
100
+ const pageCheckEnd = Math.min(pOffset + pLimit, checkEnd);
101
+ for (let i = pageCheckStart; i < pageCheckEnd; i++) {
102
+ if (!map.has(i)) {
103
+ hasMissing = true;
104
+ break;
105
+ }
106
+ }
107
+
108
+ if (hasMissing && !inflight.has(pOffset)) {
109
+ targetPageOffset = pOffset;
110
+ break;
111
+ }
112
+ }
113
+
114
+ if (targetPageOffset === -1) return;
115
+
116
+ debounceId = setTimeout(function () {
117
+ fire(targetPageOffset, pageSize);
118
+ }, fetchDebounce);
119
+ },
120
+
121
+ // Splice a fetched page. Stale (superseded-query) responses are dropped.
122
+ // Out-of-order pages splice at their own offset, so order is irrelevant.
123
+ // Returns whether the page counted as an answer — the render client keys
124
+ // its loading affordance off that.
125
+ ingest: function (detail) {
126
+ detail = detail || {};
127
+ if (detail.queryGen != null && detail.queryGen !== queryGen) return false;
128
+
129
+ const offset = detail.offset || 0;
130
+ const rows = detail.data || [];
131
+ let resolved = 0;
132
+ for (let i = 0; i < rows.length; i++) {
133
+ if (rows[i] != null) resolved++;
134
+ }
135
+
136
+ // A page that resolved nothing is not an answer in two cases. A windowed
137
+ // store whose position index was just reset answers the next request with
138
+ // pure nulls and a carried-over filtered count; and a provisional page
139
+ // states rows only, so an empty one states nothing at all. Letting either
140
+ // through consumes the swap below and blanks the view — the exact flash
141
+ // stale-while-revalidate exists to prevent. An authoritative filtered === 0
142
+ // is a different statement: the source declaring an empty result set, which
143
+ // must render the empty state.
144
+ if (resolved === 0 && (detail.provisional || detail.filtered > 0)) {
145
+ inflight.delete(offset);
146
+ return false;
147
+ }
148
+
149
+ // First response of a new generation: drop the stale rows now, at the
150
+ // swap moment, not at invalidate()/revalidate() time — stale-while-revalidate.
151
+ if (pendingSwap) {
152
+ map.clear();
153
+ touch.clear();
154
+ pendingSwap = false;
155
+ }
156
+
157
+ // A provisional page carries rows, not totals. Knowing how many records
158
+ // match requires looking at every one of them, which is exactly the work
159
+ // the local answer skips to stay fast — so the counts and the spacer
160
+ // geometry hold at whatever the last authoritative answer established.
161
+ if (!detail.provisional) {
162
+ grandTotal = detail.total != null ? detail.total : grandTotal;
163
+ logicalTotal = detail.filtered != null
164
+ ? detail.filtered
165
+ : (detail.data ? detail.data.length : logicalTotal);
166
+ }
167
+
168
+ for (let i = 0; i < rows.length; i++) {
169
+ // A windowed source sends null for a position it has not resolved
170
+ // yet. That is absence, not a record — keeping it out of the map is
171
+ // what makes has() honest and renders a placeholder instead.
172
+ if (rows[i] == null) continue;
173
+ map.set(offset + i, rows[i]);
174
+ stamp(offset + i);
175
+ }
176
+ inflight.delete(offset);
177
+ evict();
178
+ onChange();
179
+ return true;
180
+ },
181
+
182
+ // First load: fetch page 0 at the current generation (no bump).
183
+ requestInitial: function (q) {
184
+ if (q) query = q;
185
+ fire(0, pageSize);
186
+ },
187
+
188
+ // Query change: new generation, stale rows stay visible until the first
189
+ // response of the new generation lands in ingest() — no blanking, no
190
+ // placeholder flash (ln-table--loading is the refresh affordance).
191
+ invalidate: function (q) {
192
+ queryGen++;
193
+ inflight.clear();
194
+ clearTimeout(debounceId);
195
+ if (q) query = q;
196
+ pendingSwap = true;
197
+ fire(0, pageSize);
198
+ },
199
+
200
+ // Post-mutation refresh of a windowed view: same stale-while-revalidate
201
+ // swap as invalidate(), but re-requests the page at the CURRENT scroll
202
+ // position instead of jumping back to page 0.
203
+ revalidate: function () {
204
+ queryGen++;
205
+ inflight.clear();
206
+ clearTimeout(debounceId);
207
+ pendingSwap = true;
208
+ const offset = Math.max(0, Math.floor(lastRangeStart / pageSize) * pageSize);
209
+ fire(offset, pageSize);
210
+ },
211
+
212
+ // Failed page fetch: release the offset so the next ensure() (scroll,
213
+ // filter, resize) can re-request it. No onChange(), no auto-retry.
214
+ release: function (offset) {
215
+ inflight.delete(offset);
216
+ },
217
+
218
+ destroy: function () {
219
+ clearTimeout(debounceId);
220
+ map.clear();
221
+ touch.clear();
222
+ inflight.clear();
223
+ },
224
+
225
+ configure: function (partial) {
226
+ partial = partial || {};
227
+ let geometryChanged = false;
228
+ if (partial.windowSize != null && partial.windowSize > 0 && partial.windowSize !== windowSize) {
229
+ const shrank = partial.windowSize < windowSize;
230
+ windowSize = partial.windowSize;
231
+ if (shrank) evict();
232
+ geometryChanged = true;
233
+ }
234
+ if (partial.pageSize != null && partial.pageSize > 0) pageSize = partial.pageSize;
235
+ if (partial.threshold != null && partial.threshold >= 0) threshold = partial.threshold;
236
+ if (partial.fetchDebounce != null && partial.fetchDebounce >= 0) fetchDebounce = partial.fetchDebounce;
237
+ if (geometryChanged) onChange();
238
+ },
239
+
240
+ setGrandTotal: function (n) {
241
+ if (n == null || isNaN(n) || n < 0) return;
242
+ grandTotal = n;
243
+ if (!hasActiveQuery()) logicalTotal = n;
244
+ onChange();
245
+ }
246
+ };
247
+ }
@@ -1,5 +1,7 @@
1
1
  # `data-ln-couchdb-connector`
2
2
 
3
+ > Applied to a gateway element (`<div data-ln-couchdb-connector data-ln-couchdb-url="..." data-ln-couchdb-db="...">`) inside a coordinator. It listens for database request CustomEvents (`ln-couchdb-connector:request-sync`, `create`, `update`, `delete`, `bulk-delete`), queries CouchDB `_changes` feeds with sequence tokens for delta sync, and maps `id` to `_id`/`_rev` on mutations via REST `fetch()`. Upon resolution, it emits `ln-couchdb-connector:fetched` or mutation response events to the parent coordinator.
4
+
3
5
  A zero-dependency, Local-First sync transport component that implements the Transport Gateway pattern of `ln-ashlar` for CouchDB and Sync Gateway instances.
4
6
 
5
7
  This component encapsulates all connection parameters (CouchDB base URL, database name, auth credentials, headers) and provides a declarative, event-driven, or programmatic way to talk to any CouchDB-compatible backend using standard Changes Feed (`_changes`) protocols. It isolates networking concerns completely, making your cache store (`data-ln-data-store`) and visual presentation layers fully network-agnostic.
@@ -35,8 +37,8 @@ All attributes are dynamically observed. Any runtime changes to these attributes
35
37
  | Attribute | Category | Description |
36
38
  |-----------|----------|-------------|
37
39
  | `data-ln-couchdb-connector` | Selector | Creates the component instance. |
38
- | `data-ln-couchdb-url` | Connection | The base URL of the CouchDB Server or Sync Gateway (e.g. `https://couch.example.com`). Fallbacks: `data-ln-couchdb-connector-url`, `data-ln-api-base-url`, `data-ln-rest-base-url`. |
39
- | `data-ln-couchdb-db` | Connection | Database name endpoint (e.g. `tasks`). Fallbacks: `data-ln-couchdb-connector-db`, `data-ln-api-path`, `data-ln-rest-path`. |
40
+ | `data-ln-couchdb-url` | Connection | The base URL of the CouchDB Server or Sync Gateway (e.g. `https://couch.example.com`). |
41
+ | `data-ln-couchdb-db` | Connection | Database name endpoint (e.g. `tasks`). |
40
42
  | `data-ln-couchdb-auth` | Credentials | Authorization header value (e.g. `Basic dXNlcjpwYXNz` or standard token). |
41
43
  | `data-ln-couchdb-headers` | Credentials | JSON-formatted string of custom request headers. |
42
44
 
@@ -81,7 +83,7 @@ connector.bulkDelete(["doc_17", "doc_23"])
81
83
 
82
84
  ### Commands (Dispatched TO the connector)
83
85
 
84
- You can trigger mutations and fetches asynchronously by dispatching standard events directly on the connector DOM element. All events are supported in `ln-couchdb-connector`, `ln-api-connector`, and `ln-rest-connector` namespaces for 100% backward compatibility.
86
+ You can trigger mutations and fetches asynchronously by dispatching standard events directly on the connector DOM element.
85
87
 
86
88
  | Event | `detail` Payload | Description |
87
89
  |-------|------------------|-------------|
@@ -141,7 +143,7 @@ Here is how a parent Coordinator links a Cache Store and the CouchDB Connector u
141
143
  // }));
142
144
  // });
143
145
  //
144
- // See js/ln-data-coordinator/README.md for the full fan-out + error
146
+ // See components/ln-data-coordinator/README.md for the full fan-out + error
145
147
  // reconciliation policy (auth/transient/deterministic) that ships with
146
148
  // the coordinator — this connector never needs to be wired by hand.
147
149
  })();
@@ -151,7 +153,7 @@ Here is how a parent Coordinator links a Cache Store and the CouchDB Connector u
151
153
 
152
154
  ## 🔧 Internals
153
155
 
154
- Source: `js/ln-couchdb-connector/*`. Bridges CouchDB's revision-based (`_rev`) document protocol and `_changes`/`_bulk_docs` endpoints to the same coordinator-facing event contract as `ln-api-connector`.
156
+ Source: `components/ln-couchdb-connector/*`. Bridges CouchDB's revision-based (`_rev`) document protocol and `_changes`/`_bulk_docs` endpoints to the same coordinator-facing event contract as `ln-api-connector`.
155
157
 
156
158
  ### Sync flow
157
159
 
@@ -0,0 +1 @@
1
+ (function(){"use strict";function B(){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 L(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 r=null;for(let i=1;i<t.length;i++)if(t[i]&&t[i].nodeType===1){r=t[i];break}if(!L(r))return}e.apply(console,t)}}function v(e,t,n){const r=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,r),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:r}))}function D(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){D(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}function S(...e){return e.filter(t=>t!=null&&t!=="").map((t,n)=>n===0?t.replace(/\/+$/,""):t.replace(/^\/+/,"").replace(/\/+$/,"")).filter(Boolean).join("/")}function T(e,t){return Object.assign({"Content-Type":"application/json",Accept:"application/json"},e,t?{Authorization:t}:null)}function K(e,t="ln-core"){try{return e?JSON.parse(e):{}}catch(n){return console.error(`[${t}] Invalid headers JSON:`,n),{}}}const N={};function G(e,t){N[e]=t}function Q(e){return N[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=G,window.lnCore.getDataMapper=Q);function z(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,D(function(){new MutationObserver(function(){v(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const P={};function X(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];P[n]=t}function Y(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return P[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=X,window.lnCore.getLocaleFallback=Y,window.lnCore.ensureLocaleObserver=z);const x={};function Z(e,t){x[e]||(x[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=x[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function M(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let c=0;c<n.length;c++){const a=n[c],d=a.getAttribute("data-ln-field");t[d]!=null&&(a.textContent=t[d])}const r=e.querySelectorAll("[data-ln-attr]");for(let c=0;c<r.length;c++){const a=r[c],d=a.getAttribute("data-ln-attr").split(",");for(let w=0;w<d.length;w++){const m=d[w].trim().split(":");if(m.length!==2)continue;const g=m[0].trim(),y=m[1].trim();t[y]!=null&&a.setAttribute(g,t[y])}}const i=e.querySelectorAll("[data-ln-show]");for(let c=0;c<i.length;c++){const a=i[c],d=a.getAttribute("data-ln-show");d in t&&a.classList.toggle("hidden",!t[d])}const s=e.querySelectorAll("[data-ln-class]");for(let c=0;c<s.length;c++){const a=s[c],d=a.getAttribute("data-ln-class").split(",");for(let w=0;w<d.length;w++){const m=d[w].trim().split(":");if(m.length!==2)continue;const g=m[0].trim(),y=m[1].trim();y in t&&a.classList.toggle(g,!!t[y])}}return e}function ee(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 r=0;r<n.length;r++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[r],t??null),n[r].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)M(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function H(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(c,a){return t[a]!==void 0?t[a]:""}))}const r=function(s,c){return t[c]!==void 0?t[c]:""},i=Array.from(e.querySelectorAll("*"));e.nodeType===1&&i.push(e);for(let s=0;s<i.length;s++){const c=i[s],a=c.attributes;for(let d=0;d<a.length;d++){const w=a[d];w.value.indexOf("{{")!==-1&&c.setAttribute(w.name,w.value.replace(/\{\{\s*(\w+)\s*\}\}/g,r))}}return e}function te(e,t,n,r,i,s){const c={};for(let d=0;d<e.children.length;d++){const w=e.children[d],m=w.getAttribute("data-ln-render-key");m&&(c[m]=w)}const a=document.createDocumentFragment();for(let d=0;d<t.length;d++){const w=t[d],m=String(r(w));let g=c[m];if(g)i(g,w,d);else{const y=Z(n,s);if(!y||(H(y,w),g=y.firstElementChild,!g))continue;g.setAttribute("data-ln-render-key",m),i(g,w,d)}a.appendChild(g)}e.textContent="",e.appendChild(a)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=H,window.lnCore.fill=M,window.lnCore.lnFill=ee,window.lnCore.renderList=te);function E(e,t,n){const r=e.getAttribute(t);return r===null?n:r}function ne(e,t,n){const r=parseInt(e.getAttribute(t),10);return isNaN(r)?n:r}function re(e,t,n=!1){const r=e.getAttribute(t);if(r===null)return!!n;const i=r.trim().toLowerCase();return!(i==="false"||i==="0")}function oe(e,t){return(e.getAttribute(t)||"").split(",").map(n=>n.trim()).filter(Boolean)}const j=new Map;function ie(e,t){const n=(e?e.join("|"):"")+"::"+t;if(j.has(n))return j.get(n);const r=new Set(e||[]),i=function(s,c){const a=s.getAttribute(c);return a!==null&&r.has(a)?a:t};return j.set(n,i),i}function ce(e,t,n){const r=parseFloat(e.getAttribute(t));return isNaN(r)?n:r}function se(e,t,n){const r=e.getAttribute(t);if(!r)return n;try{return JSON.parse(r)}catch{return n}}function F(e,t,n,r,i){if(!e||t===null)return!0;const s=r||"ln-component",c=e.type;if(c==="trigger"||c==="marker"||c==="string"||c==="list"||!c||t===""&&e.fallback!==void 0)return!0;const a=d=>{i?console.warn(d,i):console.warn(d)};if(c==="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(c==="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(c==="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(c==="float")return isNaN(Number(t))?(a(`[${s}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(c==="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 le(e,t,n){for(const r in n){const[i,s,c]=n[r];Object.defineProperty(e,r,{get:function(){return i(t,s,c)},enumerable:!0,configurable:!0})}return e}function ae(e){const t={};for(const n in e){const r=e[n];if(!r||!r.prop)continue;let i=r.read;if(!i&&r.type)switch(r.type){case"enum":i=ie(r.values,r.fallback);break;case"integer":i=ne;break;case"float":i=ce;break;case"boolean":i=re;break;case"list":i=oe;break;case"json":i=se;break;case"string":default:i=E;break}i||(i=E),t[r.prop]=[i,n,r.fallback]}return t}function de(e){const t={};for(const n in e){const r=e[n];r&&r.effect&&(t[n]=r.effect)}return Object.keys(t).length?t:null}function ue(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 I(e,t,n,r){if(e.nodeType!==1)return;const s=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",c=Array.from(e.querySelectorAll(s));e.matches&&e.matches(s)&&c.push(e);for(const a of c)if(!a[n]){window.lnCore._persistSink&&a.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(a,t);try{a[n]=new r(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 fe(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function he(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function W(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function we(e){const t=W(),n=e.observed||[];for(let r=0;r<n.length;r++){const i=n[r];t.byAttr.has(i)||t.byAttr.set(i,[]),t.byAttr.get(i).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const r in e.attributes){t.byDeclaredAttr.has(r)||t.byDeclaredAttr.set(r,[]);const i=t.byDeclaredAttr.get(r);i.some(s=>s.componentTag===e.componentTag)||i.push({spec:e.attributes[r],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const r=ue(e);if(r===null)t.reactiveWildcard.push(e);else for(const i of r)t.byReactive.has(i)||t.byReactive.set(i,[]),t.byReactive.get(i).push(e)}e.persist&&t.persist.push(e)}function U(e,t,n,r){for(let i=0;i<e.length;i++){const s=e[i];if(!t[s.attribute])continue;const c=s.effects&&s.effects[n];c?c(t,n,r):s.onAttrChange&&(!s.declared||s.declared.has(n))&&s.onAttrChange(t,n,r)}}function be(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const r=W(),i=r.byAttr.get(n);if(B()&&r.byDeclaredAttr&&r.byDeclaredAttr.has(n)&&L(t)){const s=r.byDeclaredAttr.get(n),c=t.getAttribute(n);for(let a=0;a<s.length;a++)F(s[a].spec,c,n,s[a].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||i)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const s=r.byReactive.get(n);s&&U(s,t,n,e.oldValue),r.reactiveWildcard.length&&U(r.reactiveWildcard,t,n,e.oldValue)}if(i)for(let s=0;s<i.length;s++){const c=i[s];if(c.handler){c.handler(t,n,e.oldValue);continue}c.onAttributeChange&&t[c.attribute]?c.onAttributeChange(t,n):(I(t,c.selector,c.attribute,c.ComponentFn),c.onInit&&c.onInit(t))}}function pe(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,D(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{be(t[n])}catch(r){console.error("[ln-core] mutation handler failed",t[n].target,r)}}).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 ge(e){const t=J();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const r=t[n];if(r.onSubtreeChange){const i=r.query,s=e.target.nodeType===1?e.target.matches(i)?e.target:e.target.closest(i):e.target.parentElement?e.target.parentElement.closest(i):null;s&&r.onSubtreeChange(s,e)}}for(let n=0;n<e.addedNodes.length;n++){const r=e.addedNodes[n];if(r.nodeType===1)for(let i=0;i<t.length;i++){const s=t[i];I(r,s.selector,s.attribute,s.ComponentFn),s.onInit&&s.onInit(r)}}for(let n=0;n<e.removedNodes.length;n++){const r=e.removedNodes[n];if(r.nodeType===1)for(let i=0;i<t.length;i++){const s=t[i],c=s.query,a=Array.from(r.querySelectorAll(c));r.matches&&r.matches(c)&&a.push(r);for(let d=0;d<a.length;d++){const w=a[d];if(!document.contains(w)){const m=w[s.attribute];if(m&&typeof m.destroy=="function")try{m.destroy()}catch(g){console.error("["+s.attribute+"] destroy failed",w,g)}delete w[s.attribute]}}}}}}function me(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,D(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const r=t[n];if(r.type==="childList")try{ge(r)}catch(i){console.error("[ln-core] lifecycle handler failed",r.target,i)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function Ce(e,t,n,r,i={}){const s=i.extraAttributes||[],c=i.onAttributeChange||null,a=i.onSubtreeChange||null,d=i.onInit||null,w=i.onAttrChange||null,m=i.effects||null,g=i.attributes||null,y=g?de(g):m,$=g?new Set(Object.keys(g)):null,o=i.persist||null;function u(h){const p=h||document.body;if(I(p,e,t,n),g&&B())for(const _ in g){const R=g[_],A=Array.from(p.querySelectorAll("["+_+"]"));p.matches&&p.matches("["+_+"]")&&A.push(p);for(let O=0;O<A.length;O++){const k=A[O];L(k)&&F(R,k.getAttribute(_),_,r,k)}}d&&d(p)}const l=[];if(e.indexOf("[")!==-1){const h=/\[([\w-]+)/g;let p;for(;(p=h.exec(e))!==null;)l.push(p[1])}else l.push(e);we({selector:e,attribute:t,componentTag:r,attributes:g,ComponentFn:n,onInit:d,observed:l.concat(s),onAttributeChange:c,onAttrChange:w,effects:y,declared:$,persist:o}),pe();const b=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";J().push({selector:e,attribute:t,ComponentFn:n,onInit:d,onSubtreeChange:a,query:b}),me(),window[t]=u;function C(){fe()>0?he(function(){u(document.body)}):u(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",C):C(),u}function V(e){return(e||"").replace(/^#/,"")}function q(e){const t=e===void 0?location.hash:e,n={},r=V(t);if(!r)return n;const i=r.split("&");for(let s=0;s<i.length;s++){const c=i[s];if(!c)continue;const a=c.indexOf(":"),d=a>-1?c.slice(0,a):c,w=a>-1?c.slice(a+1):"";if(d)try{n[d]=decodeURIComponent(w)}catch{n[d]=w}}return n}function ye(e){if(!e)return null;const t=q();return e in t?t[e]:null}function _e(e,t){if(!e)return;const n=q();t==null?delete n[e]:n[e]=String(t);const i=Object.keys(n).map(function(s){const c=n[s];return c===""?s:s+":"+encodeURIComponent(c)}).join("&");V(location.hash)!==i&&(location.hash=i)}function ve(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function Ae(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 r=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return r?t?r+"-"+t:r:t||null}function ke(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function Se(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 Oe(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function Te(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),r=e.slice(t+1),i=r?r.split(",").map(function(s){try{return decodeURIComponent(s)}catch{return s}}).filter(Boolean):[];return{key:n,values:i}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=q,window.lnCore.hashGet=ye,window.lnCore.hashSet=_e,window.lnCore.hashLinkClick=ve,window.lnCore.resolveHashNamespace=Ae,window.lnCore.hashSortEncode=ke,window.lnCore.hashSortDecode=Se,window.lnCore.hashFilterEncode=Oe,window.lnCore.hashFilterDecode=Te),(function(){const e="data-ln-couchdb-connector",t="lnCouchDbConnector",n="lnConnector";if(window[t]!==void 0)return;function r(o){const u=o[t];u&&u.refreshConfig()}const i={"data-ln-couchdb-connector":{type:"marker",description:"Mounts CouchDB/PouchDB connector bridging database and ln-ashlar data coordinators"},"data-ln-couchdb-url":{prop:"url",read:E,type:"string",fallback:"",effect:r,description:"CouchDB server base endpoint URL"},"data-ln-couchdb-db":{prop:"db",read:E,type:"string",fallback:"",effect:r,description:"Target CouchDB database name"},"data-ln-couchdb-auth":{prop:"auth",read:E,type:"string",fallback:"",effect:r,description:"Authentication credentials for CouchDB requests"},"data-ln-couchdb-headers":{effect:r,type:"json",fallback:null,description:"Custom HTTP headers in JSON or semicolon-separated format"}},s=ae(i);function c(o){const u=o&&o.content!==void 0?o.content:o,l=o&&o.message?o.message:null;return{content:u,message:l}}function a(o){return this.dom=o,le(this,o,s),o[t]=this,o[n]=this,this.refreshConfig(),this._handlers=null,$(this),this}a.prototype.refreshConfig=function(){const o=this.dom;this.credentials="same-origin";const u=o.getAttribute("data-ln-couchdb-headers")||"";this.headers=K(u,"ln-couchdb-connector"),this.auth&&console.warn("[ln-couchdb-connector] Security Warning: Sensitive authorization credentials detected in data-ln-couchdb-auth attribute. Storing basic authentication credentials in HTML DOM attributes is highly discouraged and vulnerable to XSS credential extraction. Please use HttpOnly session cookies or a Backend Proxy Gateway instead."),u.toLowerCase().includes("authorization")&&console.warn("[ln-couchdb-connector] Security Warning: Sensitive authorization credentials detected in data-ln-couchdb-headers attribute. Please use HttpOnly session cookies or a Backend Proxy Gateway instead."),v(o,"ln-couchdb-connector:config-changed",{url:this.url,db:this.db,auth:this.auth?"[REDACTED]":"",headers:this.headers})};function d(o,u,l){const f=Object.assign({},T(o.headers,o.auth),l||{});return u&&(f["Idempotency-Key"]=u),f}a.prototype.fetchDelta=function(o){const u=this,l=["include_docs=true","feed=normal"];o&&l.push("since="+encodeURIComponent(o));const f=S(u.url,u.db,"_changes")+"?"+l.join("&");return window.fetch(f,{method:"GET",headers:T(u.headers,u.auth),credentials:u.credentials}).then(b=>{if(!b.ok)throw new Error("HTTP "+b.status+": "+b.statusText);return b.json()}).then(b=>{const C=b.results||[];return{data:C.filter(h=>!h.deleted&&h.doc).map(h=>Object.assign({},h.doc,{id:h.doc._id})),deleted:C.filter(h=>h.deleted).map(h=>h.id),synced_at:b.last_seq||o||""}})};function w(o,u,l){const f=Object.assign({_id:u.id},u);return f._id||delete f._id,window.fetch(S(o.url,o.db),{method:"POST",headers:d(o,l),credentials:o.credentials,body:JSON.stringify(f)}).then(b=>{if(!b.ok)throw new Error("HTTP "+b.status+": "+b.statusText);return b.json()}).then(b=>{const C=c(b),h=C.content;return{record:Object.assign({},f,{id:h.id,_id:h.id,_rev:h.rev}),message:C.message}})}a.prototype.create=function(o,u){return w(this,o,u).then(l=>l.record)};function m(o,u,l,f){const b=Object.assign({id:String(u),_id:String(u)},l),C=b._rev||b.rev;return(C?Promise.resolve(C):window.fetch(S(o.url,o.db,null,u),{method:"GET",headers:T(o.headers,o.auth),credentials:o.credentials}).then(p=>{if(!p.ok)throw new Error("Could not retrieve document for revision mapping");return p.json().then(_=>_._rev)})).then(p=>{const _=Object.assign({},b,{_rev:p});delete _.rev;const R=d(o,f,{"If-Match":p});return window.fetch(S(o.url,o.db,null,u),{method:"PUT",headers:R,credentials:o.credentials,body:JSON.stringify(_)}).then(A=>{if(A.ok)return A.json().then(O=>{const k=c(O);return{record:Object.assign({},_,{_rev:k.content.rev}),message:k.message}});if(A.status===409)return A.json().then(O=>{const k=new Error("Conflict");throw k.status=409,k.data=O,k});throw new Error("HTTP "+A.status+": "+A.statusText)})})}a.prototype.update=function(o,u,l){return m(this,o,u,l).then(f=>f.record)};function g(o,u,l,f){return(l?Promise.resolve(l):window.fetch(S(o.url,o.db,null,u),{method:"GET",headers:T(o.headers,o.auth),credentials:o.credentials}).then(C=>{if(!C.ok)throw new Error("Could not retrieve document for revision delete");return C.json().then(h=>h._rev)})).then(C=>{const h=S(o.url,o.db,null,u)+"?rev="+encodeURIComponent(C);return window.fetch(h,{method:"DELETE",headers:d(o,f),credentials:o.credentials}).then(p=>{if(!p.ok)throw new Error("HTTP "+p.status+": "+p.statusText);return p.json()}).then(p=>{const _=c(p);return{response:_.content,message:_.message}})})}a.prototype.delete=function(o,u,l){return g(this,o,u,l).then(f=>f.response)};function y(o,u,l){return!u||u.length===0?Promise.resolve({response:{ok:!0,deletedCount:0},message:null}):window.fetch(S(o.url,o.db,"_all_docs"),{method:"POST",headers:T(o.headers,o.auth),credentials:o.credentials,body:JSON.stringify({keys:u})}).then(f=>{if(!f.ok)throw new Error("HTTP "+f.status+": "+f.statusText);return f.json()}).then(f=>{const C=(f.rows||[]).filter(h=>!h.error&&h.value&&h.value.rev).map(h=>({_id:h.id,_rev:h.value.rev,_deleted:!0}));return C.length===0?{response:{ok:!0,deletedCount:0},message:null}:window.fetch(S(o.url,o.db,"_bulk_docs"),{method:"POST",headers:d(o,l),credentials:o.credentials,body:JSON.stringify({docs:C})}).then(h=>{if(!h.ok)throw new Error("HTTP "+h.status+": "+h.statusText);return h.json()}).then(h=>{const p=c(h);return{response:{ok:!0,results:p.content,deletedCount:C.length},message:p.message}})})}a.prototype.bulkDelete=function(o,u){return y(this,o,u).then(l=>l.response)};function $(o){o._handlers={sync:function(u){const l=u.detail||{};o.fetchDelta(l.since).then(function(f){v(o.dom,"ln-couchdb-connector:fetched",{data:f,since:l.since,meta:l.meta||null})}).catch(function(f){v(o.dom,"ln-couchdb-connector:error",{action:"sync",error:f.message,status:f.status||0,since:l.since,meta:l.meta||null})})},create:function(u){const l=u.detail||{};w(o,l.data,l.idempotencyKey).then(function(f){v(o.dom,"ln-couchdb-connector:created",{record:f.record,tempId:l.tempId,message:f.message,meta:l.meta||null})}).catch(function(f){v(o.dom,"ln-couchdb-connector:error",{action:"create",error:f.message,status:f.status||0,tempId:l.tempId,meta:l.meta||null})})},update:function(u){const l=u.detail||{},f=Object.assign({},l.data);l.expected_version!==void 0&&(f._rev=l.expected_version),m(o,l.id,f,l.idempotencyKey).then(function(b){v(o.dom,"ln-couchdb-connector:updated",{record:b.record,id:l.id,message:b.message,meta:l.meta||null})}).catch(function(b){v(o.dom,"ln-couchdb-connector:error",{action:"update",error:b.message,status:b.status||0,id:l.id,data:b.status===409?b.data:null,conflictData:b.status===409?b.data:null,meta:l.meta||null})})},delete:function(u){const l=u.detail||{};g(o,l.id,l.rev,l.idempotencyKey).then(function(f){v(o.dom,"ln-couchdb-connector:deleted",{response:f.response,id:l.id,message:f.message,meta:l.meta||null})}).catch(function(f){v(o.dom,"ln-couchdb-connector:error",{action:"delete",error:f.message,status:f.status||0,id:l.id,meta:l.meta||null})})},bulkDelete:function(u){const l=u.detail||{};y(o,l.ids,l.idempotencyKey).then(function(f){v(o.dom,"ln-couchdb-connector:bulk-deleted",{response:f.response,ids:l.ids,message:f.message,meta:l.meta||null})}).catch(function(f){v(o.dom,"ln-couchdb-connector:error",{action:"bulk-delete",error:f.message,status:f.status||0,ids:l.ids,meta:l.meta||null})})}},o.dom.addEventListener("ln-couchdb-connector:request-sync",o._handlers.sync),o.dom.addEventListener("ln-couchdb-connector:request-create",o._handlers.create),o.dom.addEventListener("ln-couchdb-connector:request-update",o._handlers.update),o.dom.addEventListener("ln-couchdb-connector:request-delete",o._handlers.delete),o.dom.addEventListener("ln-couchdb-connector:request-bulk-delete",o._handlers.bulkDelete)}a.prototype.destroy=function(){if(!this.dom[t])return;const o=this;o._handlers&&(o.dom.removeEventListener("ln-couchdb-connector:request-sync",o._handlers.sync),o.dom.removeEventListener("ln-couchdb-connector:request-create",o._handlers.create),o.dom.removeEventListener("ln-couchdb-connector:request-update",o._handlers.update),o.dom.removeEventListener("ln-couchdb-connector:request-delete",o._handlers.delete),o.dom.removeEventListener("ln-couchdb-connector:request-bulk-delete",o._handlers.bulkDelete),o._handlers=null),delete this.dom[t],delete this.dom[n]},Ce(e,t,a,"ln-couchdb-connector",{attributes:i})})()})();
@@ -0,0 +1,50 @@
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-couchdb-connector",
4
+ "generator": "scripts/sync-ln-schemas.mjs",
5
+ "attributes": {
6
+ "data-ln-couchdb-auth": {
7
+ "direction": null,
8
+ "sources": [
9
+ "src/ln-couchdb-connector.js"
10
+ ],
11
+ "type": "string",
12
+ "fallback": "",
13
+ "description": "Authentication credentials for CouchDB requests"
14
+ },
15
+ "data-ln-couchdb-connector": {
16
+ "direction": null,
17
+ "sources": [
18
+ "src/ln-couchdb-connector.js"
19
+ ],
20
+ "type": "marker",
21
+ "description": "Mounts CouchDB/PouchDB connector bridging database and ln-ashlar data coordinators"
22
+ },
23
+ "data-ln-couchdb-db": {
24
+ "direction": null,
25
+ "sources": [
26
+ "src/ln-couchdb-connector.js"
27
+ ],
28
+ "type": "string",
29
+ "fallback": "",
30
+ "description": "Target CouchDB database name"
31
+ },
32
+ "data-ln-couchdb-headers": {
33
+ "direction": "author",
34
+ "sources": [
35
+ "src/ln-couchdb-connector.js"
36
+ ],
37
+ "type": "json",
38
+ "description": "Custom HTTP headers in JSON or semicolon-separated format"
39
+ },
40
+ "data-ln-couchdb-url": {
41
+ "direction": null,
42
+ "sources": [
43
+ "src/ln-couchdb-connector.js"
44
+ ],
45
+ "type": "string",
46
+ "fallback": "",
47
+ "description": "CouchDB server base endpoint URL"
48
+ }
49
+ }
50
+ }