@livenetworks/ashlar 1.6.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (559) hide show
  1. package/LICENSE +641 -0
  2. package/README.md +202 -86
  3. package/{js → components}/COMPONENTS.md +1116 -1108
  4. package/{js → components}/index.js +81 -58
  5. package/{js → components}/ln-accordion/README.md +7 -6
  6. package/components/ln-accordion/ln-accordion-dev.scss +8 -0
  7. package/components/ln-accordion/ln-accordion.js +1 -0
  8. package/components/ln-accordion/ln-accordion.schema.json +30 -0
  9. package/components/ln-accordion/ln-accordion.scss +8 -0
  10. package/{js → components}/ln-accordion/src/ln-accordion.js +8 -2
  11. package/{js → components}/ln-ajax/README.md +171 -160
  12. package/components/ln-ajax/ln-ajax-dev.scss +8 -0
  13. package/components/ln-ajax/ln-ajax.js +1 -0
  14. package/components/ln-ajax/ln-ajax.schema.json +30 -0
  15. package/{js → components}/ln-ajax/src/ln-ajax.js +65 -30
  16. package/{js → components}/ln-api-connector/README.md +27 -5
  17. package/components/ln-api-connector/ln-api-connector.js +1 -0
  18. package/components/ln-api-connector/ln-api-connector.schema.json +96 -0
  19. package/components/ln-api-connector/src/connector-core.js +97 -0
  20. package/components/ln-api-connector/src/ln-api-connector.js +447 -0
  21. package/{js → components}/ln-api-queue/README.md +12 -9
  22. package/components/ln-api-queue/ln-api-queue.js +1 -0
  23. package/components/ln-api-queue/ln-api-queue.schema.json +34 -0
  24. package/{js → components}/ln-api-queue/src/ln-api-queue.js +33 -14
  25. package/{js → components}/ln-api-queue/src/queue-storage.js +7 -3
  26. package/{js → components}/ln-autoresize/README.md +129 -127
  27. package/components/ln-autoresize/ln-autoresize-dev.scss +8 -0
  28. package/components/ln-autoresize/ln-autoresize.js +1 -0
  29. package/components/ln-autoresize/ln-autoresize.schema.json +22 -0
  30. package/{js → components}/ln-autoresize/src/ln-autoresize.js +8 -1
  31. package/{js → components}/ln-autosave/README.md +127 -124
  32. package/components/ln-autosave/ln-autosave-dev.scss +13 -0
  33. package/components/ln-autosave/ln-autosave.js +1 -0
  34. package/components/ln-autosave/ln-autosave.schema.json +48 -0
  35. package/components/ln-autosave/src/autosave-model.js +34 -0
  36. package/{js → components}/ln-autosave/src/ln-autosave.js +65 -58
  37. package/components/ln-chart/README.md +145 -0
  38. package/components/ln-chart/ln-chart-dev.scss +20 -0
  39. package/components/ln-chart/ln-chart.js +1 -0
  40. package/components/ln-chart/ln-chart.schema.json +146 -0
  41. package/components/ln-chart/ln-chart.scss +8 -0
  42. package/components/ln-chart/src/chart-model.js +154 -0
  43. package/components/ln-chart/src/ln-chart.js +176 -0
  44. package/{js → components}/ln-circular-progress/README.md +15 -14
  45. package/components/ln-circular-progress/ln-circular-progress-dev.scss +8 -0
  46. package/components/ln-circular-progress/ln-circular-progress.js +1 -0
  47. package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -0
  48. package/{js → components}/ln-circular-progress/src/ln-circular-progress.js +32 -50
  49. package/{js → components}/ln-confirm/README.md +69 -18
  50. package/components/ln-confirm/ln-confirm-dev.scss +24 -0
  51. package/components/ln-confirm/ln-confirm.js +1 -0
  52. package/components/ln-confirm/ln-confirm.schema.json +66 -0
  53. package/components/ln-confirm/ln-confirm.scss +24 -0
  54. package/{js → components}/ln-confirm/src/ln-confirm.js +180 -171
  55. package/{js → components}/ln-core/README.md +374 -149
  56. package/components/ln-core/attrs.js +273 -0
  57. package/components/ln-core/compare.js +40 -0
  58. package/components/ln-core/crypto.js +265 -0
  59. package/components/ln-core/date.js +50 -0
  60. package/components/ln-core/dom.js +115 -0
  61. package/components/ln-core/events.js +122 -0
  62. package/components/ln-core/form.js +136 -0
  63. package/{js → components}/ln-core/hash.js +149 -92
  64. package/components/ln-core/helpers.js +33 -0
  65. package/components/ln-core/http.js +48 -0
  66. package/components/ln-core/index.js +11 -0
  67. package/components/ln-core/lifecycle.js +403 -0
  68. package/components/ln-core/ln-core.schema.json +109 -0
  69. package/components/ln-core/locale.js +55 -0
  70. package/components/ln-core/matching.js +78 -0
  71. package/components/ln-core/number.js +125 -0
  72. package/components/ln-core/progress.js +30 -0
  73. package/components/ln-core/template.js +206 -0
  74. package/{js → components}/ln-core/window-cache.js +247 -213
  75. package/{js → components}/ln-couchdb-connector/README.md +7 -5
  76. package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
  77. package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -0
  78. package/{js → components}/ln-couchdb-connector/src/ln-couchdb-connector.js +29 -43
  79. package/{js → components}/ln-data-coordinator/README.md +109 -73
  80. package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -0
  81. package/components/ln-data-coordinator/ln-data-coordinator.js +1 -0
  82. package/components/ln-data-coordinator/ln-data-coordinator.schema.json +196 -0
  83. package/components/ln-data-coordinator/src/data-read-policy.js +41 -0
  84. package/{js → components}/ln-data-coordinator/src/ln-data-coordinator.js +411 -154
  85. package/{js → components}/ln-data-coordinator/src/mutation-receipts.js +0 -5
  86. package/{js → components}/ln-data-store/README.md +42 -17
  87. package/components/ln-data-store/ln-data-store-dev.scss +13 -0
  88. package/components/ln-data-store/ln-data-store.js +1 -0
  89. package/components/ln-data-store/ln-data-store.schema.json +84 -0
  90. package/components/ln-data-store/src/data-store-model.js +155 -0
  91. package/{js → components}/ln-data-store/src/ln-data-store.js +407 -105
  92. package/components/ln-data-store/src/window-index.js +119 -0
  93. package/{js → components}/ln-date/README.md +17 -7
  94. package/{js → components}/ln-date/ln-date-dev.scss +14 -14
  95. package/components/ln-date/ln-date.js +1 -0
  96. package/components/ln-date/ln-date.schema.json +92 -0
  97. package/components/ln-date/src/date-model.js +186 -0
  98. package/components/ln-date/src/ln-date.js +486 -0
  99. package/components/ln-debug/README.md +132 -0
  100. package/components/ln-debug/ln-debug.js +1 -0
  101. package/components/ln-debug/ln-debug.schema.json +28 -0
  102. package/components/ln-debug/src/console-sink.js +19 -0
  103. package/components/ln-debug/src/debug-verifier.js +331 -0
  104. package/components/ln-debug/src/gate.js +95 -0
  105. package/components/ln-debug/src/generated-attributes.js +299 -0
  106. package/components/ln-debug/src/ln-debug.js +60 -0
  107. package/{js → components}/ln-dropdown/README.md +150 -140
  108. package/components/ln-dropdown/ln-dropdown-dev.scss +13 -0
  109. package/components/ln-dropdown/ln-dropdown.js +1 -0
  110. package/components/ln-dropdown/ln-dropdown.schema.json +90 -0
  111. package/components/ln-dropdown/ln-dropdown.scss +18 -0
  112. package/{js → components}/ln-dropdown/src/ln-dropdown.js +114 -11
  113. package/{js → components}/ln-editor/README.md +11 -9
  114. package/components/ln-editor/ln-editor-dev.scss +18 -0
  115. package/components/ln-editor/ln-editor.js +1 -0
  116. package/components/ln-editor/ln-editor.schema.json +58 -0
  117. package/components/ln-editor/ln-editor.scss +13 -0
  118. package/{js → components}/ln-editor/src/ln-editor.js +59 -11
  119. package/{js → components}/ln-external-links/README.md +10 -8
  120. package/components/ln-external-links/ln-external-links.js +1 -0
  121. package/components/ln-external-links/ln-external-links.schema.json +18 -0
  122. package/{js → components}/ln-external-links/src/ln-external-links.js +13 -11
  123. package/{js → components}/ln-fill/README.md +6 -8
  124. package/components/ln-fill/ln-fill.js +1 -0
  125. package/components/ln-fill/ln-fill.schema.json +23 -0
  126. package/{js → components}/ln-fill/src/ln-fill.js +7 -1
  127. package/components/ln-filter/README.md +131 -0
  128. package/components/ln-filter/ln-filter-dev.scss +13 -0
  129. package/components/ln-filter/ln-filter.js +1 -0
  130. package/components/ln-filter/ln-filter.schema.json +153 -0
  131. package/components/ln-filter/src/filter-model.js +185 -0
  132. package/components/ln-filter/src/ln-filter.js +435 -0
  133. package/{js → components}/ln-form/README.md +260 -264
  134. package/components/ln-form/ln-form-dev.scss +8 -0
  135. package/components/ln-form/ln-form.js +1 -0
  136. package/components/ln-form/ln-form.schema.json +45 -0
  137. package/{js → components}/ln-form/src/ln-form.js +107 -99
  138. package/{js → components}/ln-http/README.md +11 -6
  139. package/components/ln-http/ln-http.js +1 -0
  140. package/components/ln-http/ln-http.schema.json +6 -0
  141. package/components/ln-http/src/http-core.js +51 -0
  142. package/{js → components}/ln-http/src/ln-http.js +28 -33
  143. package/{js → components}/ln-icon/README.md +16 -9
  144. package/components/ln-icon/ln-icon.schema.json +6 -0
  145. package/components/ln-include/README.md +75 -0
  146. package/components/ln-include/ln-include-dev.scss +13 -0
  147. package/components/ln-include/ln-include.js +1 -0
  148. package/components/ln-include/ln-include.schema.json +23 -0
  149. package/components/ln-include/src/ln-include.js +111 -0
  150. package/components/ln-key/README.md +130 -0
  151. package/components/ln-key/ln-key-dev.scss +18 -0
  152. package/components/ln-key/ln-key.js +1 -0
  153. package/components/ln-key/ln-key.schema.json +56 -0
  154. package/components/ln-key/src/key-model.js +146 -0
  155. package/components/ln-key/src/ln-key.js +201 -0
  156. package/{js → components}/ln-link/README.md +7 -9
  157. package/components/ln-link/ln-link-dev.scss +8 -0
  158. package/components/ln-link/ln-link.js +1 -0
  159. package/components/ln-link/ln-link.schema.json +22 -0
  160. package/{js → components}/ln-link/src/ln-link.js +16 -11
  161. package/components/ln-list/README.md +152 -0
  162. package/components/ln-list/ln-list-dev.scss +8 -0
  163. package/components/ln-list/ln-list.js +1 -0
  164. package/components/ln-list/ln-list.schema.json +166 -0
  165. package/components/ln-list/ln-list.scss +25 -0
  166. package/{js → components}/ln-list/src/ln-list.js +1301 -1216
  167. package/{js → components}/ln-modal/README.md +13 -10
  168. package/components/ln-modal/ln-modal-dev.scss +18 -0
  169. package/components/ln-modal/ln-modal.js +1 -0
  170. package/components/ln-modal/ln-modal.schema.json +54 -0
  171. package/components/ln-modal/ln-modal.scss +51 -0
  172. package/{js → components}/ln-modal/src/ln-modal.js +164 -137
  173. package/{js → components}/ln-nav/README.md +11 -11
  174. package/components/ln-nav/ln-nav.js +1 -0
  175. package/components/ln-nav/ln-nav.schema.json +25 -0
  176. package/{js → components}/ln-nav/src/ln-nav.js +25 -14
  177. package/components/ln-number/README.md +205 -0
  178. package/{js → components}/ln-number/ln-number-dev.scss +13 -13
  179. package/components/ln-number/ln-number.js +1 -0
  180. package/components/ln-number/ln-number.schema.json +63 -0
  181. package/components/ln-number/src/ln-number.js +400 -0
  182. package/components/ln-number/src/number-model.js +31 -0
  183. package/components/ln-obfuscator/README.md +60 -0
  184. package/components/ln-obfuscator/ln-obfuscator.js +1 -0
  185. package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -0
  186. package/components/ln-obfuscator/src/ln-obfuscator.js +159 -0
  187. package/components/ln-obfuscator/src/obfuscator-model.js +250 -0
  188. package/{js → components}/ln-options/README.md +3 -1
  189. package/components/ln-options/ln-options-dev.scss +13 -0
  190. package/components/ln-options/ln-options.js +1 -0
  191. package/components/ln-options/ln-options.schema.json +41 -0
  192. package/{js → components}/ln-options/src/ln-options.js +13 -5
  193. package/components/ln-persist/README.md +151 -0
  194. package/components/ln-persist/ln-persist.js +1 -0
  195. package/components/ln-persist/ln-persist.schema.json +28 -0
  196. package/components/ln-persist/src/ln-persist.js +83 -0
  197. package/components/ln-picklist/README.md +230 -0
  198. package/components/ln-picklist/ln-picklist-dev.scss +22 -0
  199. package/components/ln-picklist/ln-picklist.js +1 -0
  200. package/components/ln-picklist/ln-picklist.schema.json +49 -0
  201. package/components/ln-picklist/src/ln-picklist.js +228 -0
  202. package/{js → components}/ln-popover/README.md +164 -162
  203. package/components/ln-popover/ln-popover-dev.scss +13 -0
  204. package/components/ln-popover/ln-popover.js +1 -0
  205. package/components/ln-popover/ln-popover.schema.json +82 -0
  206. package/components/ln-popover/ln-popover.scss +18 -0
  207. package/{js → components}/ln-popover/src/ln-popover.js +42 -36
  208. package/{js → components}/ln-progress/README.md +410 -413
  209. package/components/ln-progress/ln-progress-dev.scss +8 -0
  210. package/components/ln-progress/ln-progress.js +1 -0
  211. package/components/ln-progress/ln-progress.schema.json +40 -0
  212. package/components/ln-progress/src/ln-progress.js +91 -0
  213. package/components/ln-progress/src/progress-model.js +20 -0
  214. package/{js → components}/ln-router/README.md +443 -432
  215. package/components/ln-router/ln-router-dev.scss +13 -0
  216. package/components/ln-router/ln-router.js +1 -0
  217. package/components/ln-router/ln-router.schema.json +68 -0
  218. package/{js → components}/ln-router/src/ln-router.js +585 -539
  219. package/components/ln-router/src/router-model.js +50 -0
  220. package/components/ln-scroll/README.md +45 -0
  221. package/components/ln-scroll/ln-scroll.js +1 -0
  222. package/components/ln-scroll/ln-scroll.schema.json +85 -0
  223. package/components/ln-scroll/src/ln-scroll.js +150 -0
  224. package/components/ln-search/README.md +188 -0
  225. package/components/ln-search/ln-search-dev.scss +13 -0
  226. package/components/ln-search/ln-search.js +1 -0
  227. package/components/ln-search/ln-search.schema.json +103 -0
  228. package/components/ln-search/src/ln-search.js +330 -0
  229. package/{js → components}/ln-slug/README.md +6 -3
  230. package/components/ln-slug/ln-slug-dev.scss +18 -0
  231. package/components/ln-slug/ln-slug.js +1 -0
  232. package/components/ln-slug/ln-slug.schema.json +23 -0
  233. package/{js → components}/ln-slug/src/ln-slug.js +20 -13
  234. package/components/ln-slug/src/slug-model.js +21 -0
  235. package/{js → components}/ln-sort/README.md +178 -170
  236. package/{js → components}/ln-sort/ln-sort-dev.scss +8 -8
  237. package/components/ln-sort/ln-sort.js +1 -0
  238. package/components/ln-sort/ln-sort.schema.json +104 -0
  239. package/components/ln-sort/src/ln-sort.js +321 -0
  240. package/components/ln-sort/src/sort-model.js +117 -0
  241. package/{js → components}/ln-sortable/README.md +7 -11
  242. package/components/ln-sortable/ln-sortable-dev.scss +13 -0
  243. package/components/ln-sortable/ln-sortable.js +1 -0
  244. package/components/ln-sortable/ln-sortable.schema.json +36 -0
  245. package/{js → components}/ln-sortable/src/ln-sortable.js +8 -13
  246. package/{js → components}/ln-stat/README.md +3 -1
  247. package/components/ln-stat/ln-stat-dev.scss +8 -0
  248. package/components/ln-stat/ln-stat.js +1 -0
  249. package/components/ln-stat/ln-stat.schema.json +32 -0
  250. package/{js → components}/ln-stat/src/ln-stat.js +14 -18
  251. package/components/ln-stat/src/stat-model.js +28 -0
  252. package/{js → components}/ln-table/README.md +37 -24
  253. package/{js → components}/ln-table/ln-table-dev.scss +17 -17
  254. package/components/ln-table/ln-table.js +1 -0
  255. package/components/ln-table/ln-table.schema.json +211 -0
  256. package/components/ln-table/ln-table.scss +15 -0
  257. package/{js → components}/ln-table/src/ln-table.js +1365 -1493
  258. package/components/ln-table/src/table-model.js +98 -0
  259. package/components/ln-table-coordinator/README.md +61 -0
  260. package/components/ln-table-coordinator/ln-table-coordinator.js +1 -0
  261. package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -0
  262. package/components/ln-table-coordinator/src/ln-table-coordinator.js +193 -0
  263. package/{js → components}/ln-tabs/README.md +32 -14
  264. package/components/ln-tabs/ln-tabs-dev.scss +24 -0
  265. package/components/ln-tabs/ln-tabs.js +1 -0
  266. package/components/ln-tabs/ln-tabs.schema.json +75 -0
  267. package/components/ln-tabs/ln-tabs.scss +8 -0
  268. package/components/ln-tabs/src/ln-tabs.js +207 -0
  269. package/components/ln-tabs/src/tabs-model.js +82 -0
  270. package/{js → components}/ln-time/README.md +96 -95
  271. package/components/ln-time/ln-time-dev.scss +13 -0
  272. package/components/ln-time/ln-time.js +1 -0
  273. package/components/ln-time/ln-time.schema.json +38 -0
  274. package/{js → components}/ln-time/src/ln-time.js +206 -223
  275. package/components/ln-time/src/time-model.js +64 -0
  276. package/{js → components}/ln-toast/README.md +23 -5
  277. package/components/ln-toast/ln-toast-dev.scss +8 -0
  278. package/components/ln-toast/ln-toast.js +1 -0
  279. package/components/ln-toast/ln-toast.schema.json +65 -0
  280. package/components/ln-toast/ln-toast.scss +59 -0
  281. package/{js → components}/ln-toast/src/ln-toast.js +233 -232
  282. package/{js → components}/ln-toggle/README.md +198 -196
  283. package/{js → components}/ln-toggle/ln-toggle-dev.scss +13 -13
  284. package/components/ln-toggle/ln-toggle.js +1 -0
  285. package/components/ln-toggle/ln-toggle.schema.json +52 -0
  286. package/components/ln-toggle/ln-toggle.scss +37 -0
  287. package/{js → components}/ln-toggle/src/ln-toggle.js +61 -46
  288. package/{js → components}/ln-tooltip/README.md +6 -6
  289. package/{js → components}/ln-tooltip/ln-tooltip-dev.scss +9 -9
  290. package/components/ln-tooltip/ln-tooltip.js +1 -0
  291. package/components/ln-tooltip/ln-tooltip.schema.json +86 -0
  292. package/components/ln-tooltip/ln-tooltip.scss +9 -0
  293. package/{js → components}/ln-tooltip/src/ln-tooltip.js +14 -3
  294. package/{js → components}/ln-translations/README.md +3 -1
  295. package/components/ln-translations/ln-translations-dev.scss +13 -0
  296. package/components/ln-translations/ln-translations.js +1 -0
  297. package/components/ln-translations/ln-translations.schema.json +120 -0
  298. package/{js → components}/ln-translations/src/ln-translations.js +25 -10
  299. package/components/ln-ui-coordinator/README.md +101 -0
  300. package/components/ln-ui-coordinator/ln-ui-coordinator-dev.scss +8 -0
  301. package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -0
  302. package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +60 -0
  303. package/{js/ln-modal-coordinator/src/ln-modal-coordinator.js → components/ln-ui-coordinator/src/ln-ui-coordinator.js} +403 -345
  304. package/components/ln-upload/README.md +133 -0
  305. package/components/ln-upload/ln-upload-dev.scss +18 -0
  306. package/components/ln-upload/ln-upload.js +1 -0
  307. package/components/ln-upload/ln-upload.schema.json +193 -0
  308. package/components/ln-upload/ln-upload.scss +20 -0
  309. package/components/ln-upload/src/ln-upload.js +652 -0
  310. package/components/ln-upload/src/upload-model.js +78 -0
  311. package/{js → components}/ln-validate/README.md +182 -180
  312. package/{js → components}/ln-validate/ln-validate-dev.scss +15 -15
  313. package/components/ln-validate/ln-validate.js +1 -0
  314. package/components/ln-validate/ln-validate.schema.json +50 -0
  315. package/components/ln-validate/ln-validate.scss +7 -0
  316. package/{js → components}/ln-validate/src/ln-validate.js +23 -45
  317. package/components/ln-validate/src/validate-model.js +64 -0
  318. package/components/ln-websocket-connector/README.md +166 -0
  319. package/components/ln-websocket-connector/ln-websocket-connector.js +1 -0
  320. package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -0
  321. package/components/ln-websocket-connector/src/ln-websocket-connector.js +279 -0
  322. package/ln-ashlar.html-data.json +1796 -0
  323. package/package.json +84 -61
  324. package/{scss → theme}/base/_global.scss +1 -2
  325. package/{scss → theme}/base/_reset.scss +1 -1
  326. package/{scss → theme}/base/_typography.scss +2 -0
  327. package/theme/brand.css +73 -0
  328. package/{scss → theme}/components/_app-shell.scss +8 -0
  329. package/theme/components/_button.scss +24 -0
  330. package/theme/components/_chart.scss +5 -0
  331. package/theme/components/_confirm.scss +6 -0
  332. package/{scss → theme}/components/_date.scss +30 -22
  333. package/{scss → theme}/components/_dropdown.scss +6 -1
  334. package/theme/components/_form.scss +140 -0
  335. package/{scss → theme}/components/_layout.scss +6 -0
  336. package/{scss → theme}/components/_ln-table.scss +1 -6
  337. package/theme/components/_picklist.scss +3 -0
  338. package/{scss → theme}/components/_sort.scss +10 -10
  339. package/theme/components/_status-badge.scss +6 -0
  340. package/{scss → theme}/components/_table.scss +16 -0
  341. package/{scss → theme}/components/_tabs.scss +0 -4
  342. package/theme/components/_toast.scss +48 -0
  343. package/{scss → theme}/components/_toggle.scss +1 -1
  344. package/theme/components/_upload.scss +45 -0
  345. package/{scss → theme}/config/_breakpoints.scss +1 -1
  346. package/theme/config/_contrast.scss +128 -0
  347. package/{scss → theme}/config/_density.scss +191 -205
  348. package/theme/config/_palette.scss +274 -0
  349. package/theme/config/_theme.scss +293 -0
  350. package/{scss → theme}/config/_tokens.scss +285 -441
  351. package/{scss → theme}/config/mixins/_accordion.scss +1 -1
  352. package/{scss → theme}/config/mixins/_alert.scss +1 -0
  353. package/{scss → theme}/config/mixins/_app-shell.scss +4 -2
  354. package/{scss → theme}/config/mixins/_borders.scss +2 -0
  355. package/theme/config/mixins/_btn.scss +175 -0
  356. package/{scss → theme}/config/mixins/_card.scss +55 -46
  357. package/theme/config/mixins/_chart.scss +82 -0
  358. package/{scss → theme}/config/mixins/_collapsible.scss +2 -1
  359. package/{scss → theme}/config/mixins/_colors.scss +8 -14
  360. package/{scss → theme}/config/mixins/_diagnostics.scss +48 -48
  361. package/theme/config/mixins/_dropdown.scss +169 -0
  362. package/{scss → theme}/config/mixins/_editor.scss +0 -7
  363. package/{scss → theme}/config/mixins/_filter.scss +47 -47
  364. package/{scss → theme}/config/mixins/_footer.scss +1 -1
  365. package/{scss → theme}/config/mixins/_form.scss +49 -18
  366. package/{scss → theme}/config/mixins/_index.scss +62 -61
  367. package/{scss → theme}/config/mixins/_layout.scss +6 -2
  368. package/{scss → theme}/config/mixins/_ln-table.scss +31 -10
  369. package/{scss → theme}/config/mixins/_loader.scss +1 -1
  370. package/{scss → theme}/config/mixins/_modal.scss +145 -149
  371. package/{scss → theme}/config/mixins/_motion.scss +13 -0
  372. package/{scss → theme}/config/mixins/_nav.scss +7 -7
  373. package/theme/config/mixins/_picklist.scss +66 -0
  374. package/theme/config/mixins/_popover.scss +96 -0
  375. package/{scss → theme}/config/mixins/_sidebar.scss +7 -4
  376. package/{scss → theme}/config/mixins/_sort.scss +43 -42
  377. package/{scss → theme}/config/mixins/_status-badge.scss +15 -2
  378. package/{scss → theme}/config/mixins/_table.scss +25 -14
  379. package/{scss → theme}/config/mixins/_tabs.scss +1 -1
  380. package/{scss → theme}/config/mixins/_toast.scss +174 -179
  381. package/{scss → theme}/config/mixins/_tooltip.scss +2 -2
  382. package/{scss → theme}/config/mixins/_typography.scss +16 -5
  383. package/{scss → theme}/config/mixins/_upload.scss +8 -6
  384. package/theme/ln-ashlar-core.scss +24 -0
  385. package/theme/ln-ashlar-dev.scss +66 -0
  386. package/theme/ln-ashlar-landing.scss +56 -0
  387. package/{scss/ln-ashlar.scss → theme/ln-ashlar-theme.scss} +63 -69
  388. package/theme/ln-ashlar.scss +8 -0
  389. package/theme/presentation/_bento.scss +151 -0
  390. package/theme/presentation/_cta.scss +111 -0
  391. package/theme/presentation/_effects.scss +216 -0
  392. package/theme/presentation/_features.scss +108 -0
  393. package/theme/presentation/_footer.scss +129 -0
  394. package/theme/presentation/_hero.scss +158 -0
  395. package/theme/presentation/_layout.scss +170 -0
  396. package/theme/presentation/_navbar.scss +140 -0
  397. package/theme/presentation/_pricing.scss +262 -0
  398. package/theme/presentation/_stats.scss +87 -0
  399. package/theme/presentation/_testimonials.scss +124 -0
  400. package/theme/presentation/_tokens.scss +39 -0
  401. package/theme/presentation/_typography.scss +163 -0
  402. package/{scss → theme}/utilities/_animations.scss +38 -0
  403. package/{scss → theme}/utilities/_utilities.scss +6 -0
  404. package/web-types.json +2312 -0
  405. package/js/ln-accordion/ln-accordion.js +0 -1
  406. package/js/ln-ajax/ln-ajax.js +0 -1
  407. package/js/ln-api-connector/ln-api-connector.js +0 -1
  408. package/js/ln-api-connector/src/ln-api-connector.js +0 -368
  409. package/js/ln-api-queue/ln-api-queue.js +0 -1
  410. package/js/ln-autoresize/ln-autoresize.js +0 -1
  411. package/js/ln-autosave/ln-autosave.js +0 -1
  412. package/js/ln-circular-progress/ln-circular-progress.js +0 -1
  413. package/js/ln-confirm/_ln-confirm.scss +0 -24
  414. package/js/ln-confirm/ln-confirm.js +0 -1
  415. package/js/ln-core/crypto.js +0 -83
  416. package/js/ln-core/helpers.js +0 -788
  417. package/js/ln-core/index.js +0 -7
  418. package/js/ln-core/persist.js +0 -97
  419. package/js/ln-couchdb-connector/ln-couchdb-connector.js +0 -1
  420. package/js/ln-data-coordinator/ln-data-coordinator.js +0 -1
  421. package/js/ln-data-coordinator/src/data-read-policy.js +0 -18
  422. package/js/ln-data-store/ln-data-store.js +0 -1
  423. package/js/ln-date/ln-date.js +0 -1
  424. package/js/ln-date/src/ln-date.js +0 -603
  425. package/js/ln-debug/README.md +0 -58
  426. package/js/ln-debug/ln-debug.js +0 -1
  427. package/js/ln-debug/src/ln-debug.js +0 -19
  428. package/js/ln-dropdown/ln-dropdown.js +0 -1
  429. package/js/ln-dropdown/ln-dropdown.scss +0 -15
  430. package/js/ln-editor/ln-editor.js +0 -1
  431. package/js/ln-editor/ln-editor.scss +0 -43
  432. package/js/ln-external-links/ln-external-links.js +0 -1
  433. package/js/ln-fill/ln-fill.js +0 -1
  434. package/js/ln-filter/README.md +0 -189
  435. package/js/ln-filter/ln-filter-dev.scss +0 -8
  436. package/js/ln-filter/ln-filter.js +0 -1
  437. package/js/ln-filter/src/ln-filter.js +0 -419
  438. package/js/ln-form/ln-form.js +0 -1
  439. package/js/ln-http/ln-http.js +0 -1
  440. package/js/ln-link/ln-link.js +0 -1
  441. package/js/ln-list/README.md +0 -129
  442. package/js/ln-list/ln-list.js +0 -1
  443. package/js/ln-list/ln-list.scss +0 -28
  444. package/js/ln-modal/ln-modal-dev.scss +0 -13
  445. package/js/ln-modal/ln-modal.js +0 -1
  446. package/js/ln-modal/ln-modal.scss +0 -35
  447. package/js/ln-modal-coordinator/README.md +0 -99
  448. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +0 -8
  449. package/js/ln-modal-coordinator/ln-modal-coordinator.js +0 -1
  450. package/js/ln-nav/ln-nav.js +0 -1
  451. package/js/ln-number/README.md +0 -149
  452. package/js/ln-number/ln-number.js +0 -1
  453. package/js/ln-number/src/ln-number.js +0 -443
  454. package/js/ln-options/ln-options.js +0 -1
  455. package/js/ln-popover/ln-popover.js +0 -1
  456. package/js/ln-progress/ln-progress.js +0 -1
  457. package/js/ln-progress/src/ln-progress.js +0 -98
  458. package/js/ln-router/ln-router.js +0 -1
  459. package/js/ln-search/README.md +0 -158
  460. package/js/ln-search/ln-search-dev.scss +0 -8
  461. package/js/ln-search/ln-search.js +0 -1
  462. package/js/ln-search/src/ln-search.js +0 -117
  463. package/js/ln-slug/ln-slug.js +0 -1
  464. package/js/ln-sort/ln-sort.js +0 -1
  465. package/js/ln-sort/src/ln-sort.js +0 -178
  466. package/js/ln-sortable/ln-sortable.js +0 -1
  467. package/js/ln-stat/ln-stat.js +0 -1
  468. package/js/ln-table/ln-table.js +0 -1
  469. package/js/ln-table/ln-table.scss +0 -11
  470. package/js/ln-table-coordinator/README.md +0 -73
  471. package/js/ln-table-coordinator/ln-table-coordinator.js +0 -1
  472. package/js/ln-table-coordinator/src/ln-table-coordinator.js +0 -160
  473. package/js/ln-tabs/ln-tabs-dev.scss +0 -18
  474. package/js/ln-tabs/ln-tabs.js +0 -1
  475. package/js/ln-tabs/src/ln-tabs.js +0 -188
  476. package/js/ln-time/ln-time.js +0 -1
  477. package/js/ln-toast/ln-toast.js +0 -1
  478. package/js/ln-toggle/ln-toggle.js +0 -1
  479. package/js/ln-tooltip/ln-tooltip.js +0 -1
  480. package/js/ln-tooltip/ln-tooltip.scss +0 -9
  481. package/js/ln-translations/ln-translations.js +0 -1
  482. package/js/ln-upload/README.md +0 -255
  483. package/js/ln-upload/ln-upload.js +0 -1
  484. package/js/ln-upload/ln-upload.scss +0 -20
  485. package/js/ln-upload/src/ln-upload.js +0 -423
  486. package/js/ln-validate/ln-validate.js +0 -1
  487. package/scss/components/_button.scss +0 -20
  488. package/scss/components/_confirm.scss +0 -5
  489. package/scss/components/_form.scss +0 -107
  490. package/scss/components/_status-badge.scss +0 -4
  491. package/scss/components/_toast.scss +0 -68
  492. package/scss/components/_upload.scss +0 -51
  493. package/scss/config/_theme.scss +0 -216
  494. package/scss/config/mixins/_btn.scss +0 -179
  495. package/scss/config/mixins/_confirm.scss +0 -31
  496. package/scss/config/mixins/_dropdown.scss +0 -141
  497. package/scss/config/mixins/_popover.scss +0 -64
  498. package/scss/ln-ashlar-dev.scss +0 -39
  499. /package/{js → components}/ln-core/positioning.js +0 -0
  500. /package/{js → components}/ln-core/reactive.js +0 -0
  501. /package/{js → components}/ln-filter/ln-filter.scss +0 -0
  502. /package/{js → components}/ln-icon/ln-icon.js +0 -0
  503. /package/{js → components}/ln-icon/src/ln-icon.js +0 -0
  504. /package/{js → components}/ln-search/ln-search.scss +0 -0
  505. /package/{js → components}/ln-toast/template.html +0 -0
  506. /package/{scss → theme}/components/_accordion.scss +0 -0
  507. /package/{scss → theme}/components/_ajax.scss +0 -0
  508. /package/{scss → theme}/components/_alert.scss +0 -0
  509. /package/{scss → theme}/components/_avatar.scss +0 -0
  510. /package/{scss → theme}/components/_breadcrumbs.scss +0 -0
  511. /package/{scss → theme}/components/_card.scss +0 -0
  512. /package/{scss → theme}/components/_chip.scss +0 -0
  513. /package/{scss → theme}/components/_circular-progress.scss +0 -0
  514. /package/{scss → theme}/components/_editor.scss +0 -0
  515. /package/{scss → theme}/components/_empty-state.scss +0 -0
  516. /package/{scss → theme}/components/_filter.scss +0 -0
  517. /package/{scss → theme}/components/_link.scss +0 -0
  518. /package/{scss → theme}/components/_loader.scss +0 -0
  519. /package/{scss → theme}/components/_modal.scss +0 -0
  520. /package/{scss → theme}/components/_nav.scss +0 -0
  521. /package/{scss → theme}/components/_page-header.scss +0 -0
  522. /package/{scss → theme}/components/_popover.scss +0 -0
  523. /package/{scss → theme}/components/_progress.scss +0 -0
  524. /package/{scss → theme}/components/_prose.scss +0 -0
  525. /package/{scss → theme}/components/_scrollbar.scss +0 -0
  526. /package/{scss → theme}/components/_sections.scss +0 -0
  527. /package/{scss → theme}/components/_sidebar.scss +0 -0
  528. /package/{scss → theme}/components/_stat-card.scss +0 -0
  529. /package/{scss → theme}/components/_stepper.scss +0 -0
  530. /package/{scss → theme}/components/_timeline.scss +0 -0
  531. /package/{scss → theme}/components/_tooltip.scss +0 -0
  532. /package/{scss → theme}/components/_translations.scss +0 -0
  533. /package/{scss → theme}/config/_icons.scss +0 -0
  534. /package/{scss → theme}/config/_mixins.scss +0 -0
  535. /package/{scss → theme}/config/mixins/_ajax.scss +0 -0
  536. /package/{scss → theme}/config/mixins/_avatar.scss +0 -0
  537. /package/{scss → theme}/config/mixins/_breadcrumbs.scss +0 -0
  538. /package/{scss → theme}/config/mixins/_breakpoints.scss +0 -0
  539. /package/{scss → theme}/config/mixins/_chip.scss +0 -0
  540. /package/{scss → theme}/config/mixins/_circular-progress.scss +0 -0
  541. /package/{scss → theme}/config/mixins/_display.scss +0 -0
  542. /package/{scss → theme}/config/mixins/_empty-state.scss +0 -0
  543. /package/{scss → theme}/config/mixins/_focus.scss +0 -0
  544. /package/{scss → theme}/config/mixins/_interaction.scss +0 -0
  545. /package/{scss → theme}/config/mixins/_kbd.scss +0 -0
  546. /package/{scss → theme}/config/mixins/_link.scss +0 -0
  547. /package/{scss → theme}/config/mixins/_page-header.scss +0 -0
  548. /package/{scss → theme}/config/mixins/_position.scss +0 -0
  549. /package/{scss → theme}/config/mixins/_progress.scss +0 -0
  550. /package/{scss → theme}/config/mixins/_prose.scss +0 -0
  551. /package/{scss → theme}/config/mixins/_shadows.scss +0 -0
  552. /package/{scss → theme}/config/mixins/_sizing.scss +0 -0
  553. /package/{scss → theme}/config/mixins/_spacing.scss +0 -0
  554. /package/{scss → theme}/config/mixins/_stat-card.scss +0 -0
  555. /package/{scss → theme}/config/mixins/_stepper.scss +0 -0
  556. /package/{scss → theme}/config/mixins/_timeline.scss +0 -0
  557. /package/{scss → theme}/config/mixins/_transitions.scss +0 -0
  558. /package/{scss → theme}/config/mixins/_translations.scss +0 -0
  559. /package/{scss → theme}/tabler-icons.txt +0 -0
@@ -1,4 +1,6 @@
1
- import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, decryptData } from '../../ln-core';
1
+ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, decryptData, defineAttrs, attrSpec, attrInt, attrBool, attrList } from '../../ln-core';
2
+ import { createWindowIndex } from './window-index.js';
3
+ import { aggregateRecords, decorateRecords, filterRecords, queryRecords } from './data-store-model.js';
2
4
 
3
5
  (function () {
4
6
  const DOM_SELECTOR = 'data-ln-data-store';
@@ -6,6 +8,29 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
6
8
 
7
9
  if (window[DOM_ATTRIBUTE] !== undefined) return;
8
10
 
11
+ // ─── Custom Attribute Readers ───────────────────────────
12
+ // 'never' / '-1' mean "no staleness", everything unparsable means the default.
13
+ function _readStale(el, name, fallback) {
14
+ const raw = el.getAttribute(name);
15
+ if (raw === 'never' || raw === '-1') return -1;
16
+ const parsed = parseInt(raw, 10);
17
+ return isNaN(parsed) ? fallback : parsed;
18
+ }
19
+
20
+ // ─── Attribute Contract (SSOT) ──────────────────────────
21
+ const ATTRIBUTES = {
22
+ 'data-ln-data-store': { type: 'marker', effect: _markFrozen, description: 'Identifies the element as a data-store definition container' },
23
+ 'data-ln-data-store-indexes': { type: 'list', effect: _markFrozen, description: 'Comma-separated index field names for the IndexedDB store' },
24
+ 'data-ln-data-store-stale': { prop: '_staleThreshold', type: 'integer', read: _readStale, fallback: 300, description: 'Cache staleness threshold in seconds, or -1/never' },
25
+ 'data-ln-data-store-search-fields': { prop: '_searchFields', type: 'list', read: attrList, description: 'Record fields to index for client-side search' },
26
+ 'data-ln-data-store-no-local-query': { prop: 'noLocalQuery', type: 'boolean', read: attrBool, description: 'Bypasses local IndexedDB query resolution, forcing remote fetching' },
27
+ 'data-ln-data-store-window': { prop: '_windowSize', type: 'integer', read: attrInt, fallback: 1000, min: 10, effect: _applyWindowSize, description: 'Virtual scrolling cache window size in records' },
28
+ 'data-ln-data-store-window-page': { prop: '_windowPageSize', type: 'integer', read: attrInt, fallback: 200, min: 5, effect: _applyWindowPageSize, description: 'Virtual scrolling slice page size' },
29
+ 'data-ln-data-store-frozen': { type: 'marker', description: 'Applied at runtime to indicate store schema is locked in IndexedDB' }
30
+ };
31
+
32
+ const ATTR_SPEC = attrSpec(ATTRIBUTES);
33
+
9
34
  const DB_NAME = 'ln_app_cache';
10
35
  const META_STORE = '_meta';
11
36
  const SCHEMA_VERSION = '1.0';
@@ -25,7 +50,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
25
50
  function _getRequiredStores() {
26
51
  const required = {};
27
52
  for (const el of document.querySelectorAll(`[${DOM_SELECTOR}]`)) {
28
- const name = el.getAttribute(DOM_SELECTOR);
53
+ const name = el.id;
29
54
  if (name) {
30
55
  const indexAttr = el.getAttribute('data-ln-data-store-indexes') || '';
31
56
  required[name] = {
@@ -134,16 +159,14 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
134
159
  if (!encryptedPayload || !encryptedPayload.encrypted) return record;
135
160
 
136
161
  return {
137
- id: recordId,
138
- encrypted: true,
139
- iv: encryptedPayload.iv,
140
- data: encryptedPayload.data
162
+ ...encryptedPayload,
163
+ id: recordId
141
164
  };
142
165
  }
143
166
 
144
167
  async function _decryptRecord(record) {
145
168
  if (!record || !record.encrypted || !getCryptoKey()) return record;
146
- return decryptData(record);
169
+ return decryptData(record, { silent: true });
147
170
  }
148
171
 
149
172
  // ─── IndexedDB CRUD Helpers ────────────────────────────
@@ -165,15 +188,59 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
165
188
  .then(records => getCryptoKey() ? Promise.all(records.map(r => _decryptRecord(r))) : records);
166
189
 
167
190
  const _getRecord = (storeName, id) => _tx(storeName, 'readonly')
168
- .then(store => store ? _idbRequest(store.get(id)) : null)
191
+ .then(store => {
192
+ if (!store) return null;
193
+ return _idbRequest(store.get(id)).then(res => {
194
+ if (res !== undefined) return res;
195
+ if (typeof id === 'string' && id.trim() !== '' && !isNaN(Number(id))) {
196
+ return _idbRequest(store.get(Number(id)));
197
+ }
198
+ if (typeof id === 'number') {
199
+ return _idbRequest(store.get(String(id)));
200
+ }
201
+ return null;
202
+ });
203
+ })
169
204
  .then(record => record ? _decryptRecord(record) : null);
170
205
 
206
+ const _getMultipleRecords = (storeName, ids) => _getDb().then(db => {
207
+ if (!db) return [];
208
+ const tx = db.transaction(storeName, 'readonly');
209
+ const store = tx.objectStore(storeName);
210
+ const promises = ids.map(id => _idbRequest(store.get(id)).then(res => {
211
+ if (res !== undefined) return res;
212
+ if (typeof id === 'string' && id.trim() !== '' && !isNaN(Number(id))) {
213
+ return _idbRequest(store.get(Number(id)));
214
+ }
215
+ if (typeof id === 'number') {
216
+ return _idbRequest(store.get(String(id)));
217
+ }
218
+ return null;
219
+ }));
220
+ return Promise.all(promises).then(records => {
221
+ if (getCryptoKey()) {
222
+ return Promise.all(records.map(r => r ? _decryptRecord(r) : null));
223
+ }
224
+ return records;
225
+ });
226
+ });
227
+
171
228
  const _putRecord = (storeName, record) => {
172
229
  const prepPromise = getCryptoKey() ? _encryptRecord(record) : Promise.resolve(record);
173
230
  return prepPromise.then(prepped => _tx(storeName, 'readwrite').then(store => store ? _idbRequest(store.put(prepped)) : null));
174
231
  };
175
232
 
176
- const _deleteRecord = (storeName, id) => _tx(storeName, 'readwrite').then(store => store ? _idbRequest(store.delete(id)) : null);
233
+ const _deleteRecord = (storeName, id) => _tx(storeName, 'readwrite').then(store => {
234
+ if (!store) return null;
235
+ return _idbRequest(store.delete(id)).then(() => {
236
+ if (typeof id === 'string' && id.trim() !== '' && !isNaN(Number(id))) {
237
+ return _idbRequest(store.delete(Number(id)));
238
+ }
239
+ if (typeof id === 'number') {
240
+ return _idbRequest(store.delete(String(id)));
241
+ }
242
+ });
243
+ });
177
244
  const _clearStore = storeName => _tx(storeName, 'readwrite').then(store => store ? _idbRequest(store.clear()) : null);
178
245
  const _countRecords = storeName => _tx(storeName, 'readonly').then(store => store ? _idbRequest(store.count()) : 0);
179
246
 
@@ -190,23 +257,45 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
190
257
 
191
258
  function _component(dom) {
192
259
  this.dom = dom;
193
- this._name = dom.getAttribute(DOM_SELECTOR);
260
+ this._name = dom.id;
261
+ if (!this._name) console.warn('[ln-data-store] missing id — the store cannot be addressed', dom);
194
262
 
195
- const staleAttr = dom.getAttribute('data-ln-data-store-stale');
196
- const _parsed = parseInt(staleAttr, 10);
197
- this._staleThreshold = (staleAttr === 'never' || staleAttr === '-1') ? -1 : (isNaN(_parsed) ? 300 : _parsed);
198
-
199
- const searchAttr = dom.getAttribute('data-ln-data-store-search-fields') || '';
200
- this._searchFields = searchAttr.split(',').map(s => s.trim()).filter(Boolean);
263
+ defineAttrs(this, dom, ATTR_SPEC);
201
264
 
202
265
  this._handlers = null;
203
266
 
204
267
  this.isLoaded = false;
268
+ // Two different questions that shared one flag until they were split.
269
+ // isLoaded: a full sync has landed, so the cache is authoritative and sync
270
+ // staleness may be judged against it. canServe: records are held that can
271
+ // answer a read. A page fetch grants the second without granting the first.
272
+ this.canServe = false;
205
273
  this.isInitialized = false;
206
274
  this.initializationError = null;
207
275
  this.hasCache = false;
208
276
  this.isSyncing = false;
209
277
  this.lastSyncedAt = null;
278
+ this.query = { filters: {}, search: '', sort: null };
279
+ if (dom.hasAttribute('data-ln-data-store-window')) {
280
+ this._windowIndex = createWindowIndex({
281
+ windowSize: this._windowSize,
282
+ pageSize: this._windowPageSize,
283
+ requestPage: (offset, limit, query) => {
284
+ dispatch(this.dom, 'ln-data-store:request-page', {
285
+ store: this._name,
286
+ offset: offset,
287
+ limit: limit,
288
+ query: query,
289
+ queryGen: this._windowIndex.queryGen
290
+ });
291
+ }
292
+ });
293
+ } else {
294
+ this._windowIndex = null;
295
+ }
296
+ this.windowed = this._windowIndex !== null;
297
+ // Opt out of answering reads from the cache: queries wait for the server.
298
+ // Read live off the host — see the effects map at registration.
210
299
  this.totalCount = 0;
211
300
  this.presenters = null;
212
301
  this._mutationChain = Promise.resolve();
@@ -238,6 +327,50 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
238
327
  for (const [event, fn] of Object.entries(self._handlers)) {
239
328
  self.dom.addEventListener(`ln-data-store:request-${event}`, fn);
240
329
  }
330
+
331
+ self._queryHandlers = {
332
+ 'ln-search:change': e => {
333
+ e.preventDefault();
334
+ const term = (e.detail && e.detail.term != null) ? e.detail.term : '';
335
+ if (term === self.query.search) return;
336
+ self.query.search = term;
337
+ _emitQueryChanged(self);
338
+ },
339
+ 'ln-filter:change': e => {
340
+ e.preventDefault();
341
+ const key = e.detail && e.detail.key;
342
+ if (!key) return;
343
+ const values = (e.detail.values || []).slice();
344
+ // Same no-op guard the search and sort handlers carry: a reset of a
345
+ // filter that was never set is not a query change, and clear-all
346
+ // resets every filter control on the page at once.
347
+ const prev = self.query.filters[key];
348
+ const unchanged = prev
349
+ ? (prev.length === values.length && prev.every((v, i) => v === values[i]))
350
+ : !values.length;
351
+ if (unchanged) return;
352
+ if (values.length) self.query.filters[key] = values;
353
+ else delete self.query.filters[key];
354
+ _emitQueryChanged(self);
355
+ },
356
+ 'ln-sort:change': e => {
357
+ e.preventDefault();
358
+ const field = e.detail && e.detail.field;
359
+ const direction = e.detail && e.detail.direction;
360
+ // ln-sort emits direction 'none' to mean "sort removed" — a truthy
361
+ // string, so it has to be excluded explicitly or it travels to the
362
+ // server as sort_dir=none.
363
+ const next = (direction && direction !== 'none') ? { field, direction } : null;
364
+ const prev = self.query.sort;
365
+ const unchanged = (!prev && !next) || (prev && next && prev.field === next.field && prev.direction === next.direction);
366
+ if (unchanged) return;
367
+ self.query.sort = next;
368
+ _emitQueryChanged(self);
369
+ }
370
+ };
371
+ for (const [event, fn] of Object.entries(self._queryHandlers)) {
372
+ self.dom.addEventListener(event, fn);
373
+ }
241
374
  }
242
375
 
243
376
  function _queueMutation(self, action, detail, operation) {
@@ -252,16 +385,22 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
252
385
  return self._mutationChain;
253
386
  }
254
387
 
255
- function _persistMutationMeta(self) {
388
+ function _persistMutationMeta(self, deltaCount = 0) {
256
389
  return _countRecords(self._name).then(count => {
257
- self.totalCount = count;
390
+ if (self._windowIndex || self.windowed) {
391
+ const current = self.totalCount != null ? self.totalCount : count;
392
+ self.totalCount = Math.max(0, current + deltaCount);
393
+ } else {
394
+ self.totalCount = count;
395
+ }
258
396
  self.hasCache = true;
259
397
  self.isLoaded = true;
398
+ self.canServe = true;
260
399
  return _setMeta(self._name, {
261
400
  schema_version: SCHEMA_VERSION,
262
401
  last_synced_at: self.lastSyncedAt,
263
402
  has_cache: true,
264
- record_count: count
403
+ record_count: self.totalCount
265
404
  });
266
405
  });
267
406
  }
@@ -271,7 +410,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
271
410
  function _handleCreateRequest(self, { tempId, data = {}, requestId } = {}) {
272
411
  const record = { ...data, id: tempId };
273
412
 
274
- return _putRecord(self._name, record).then(() => _persistMutationMeta(self)).then(() => {
413
+ return _putRecord(self._name, record).then(() => _persistMutationMeta(self, 1)).then(() => {
275
414
  dispatch(self.dom, 'ln-data-store:created', { store: self._name, record, tempId, requestId });
276
415
  });
277
416
  }
@@ -280,16 +419,17 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
280
419
  return _getRecord(self._name, id).then(existing => {
281
420
  if (!existing) throw new Error(`Record not found: ${id}`);
282
421
 
283
- const updated = { ...existing, ...data };
422
+ const canonicalId = existing.id;
423
+ const updated = { ...existing, ...data, id: canonicalId };
284
424
  const newId = data.id;
285
- const isRekey = newId !== undefined && newId !== id;
425
+ const isRekey = newId !== undefined && newId !== canonicalId;
286
426
 
287
427
  const write = isRekey
288
- ? _rekeyRecord(self._name, id, updated)
428
+ ? _rekeyRecord(self._name, canonicalId, { ...updated, id: newId })
289
429
  : _putRecord(self._name, updated);
290
430
 
291
- return write.then(() => _persistMutationMeta(self)).then(() => {
292
- dispatch(self.dom, 'ln-data-store:updated', { store: self._name, record: updated, previous: existing, requestId });
431
+ return write.then(() => _persistMutationMeta(self, 0)).then(() => {
432
+ dispatch(self.dom, 'ln-data-store:updated', { store: self._name, record: isRekey ? { ...updated, id: newId } : updated, previous: existing, requestId });
293
433
  });
294
434
  });
295
435
  }
@@ -301,8 +441,9 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
301
441
  return;
302
442
  }
303
443
 
304
- return _deleteRecord(self._name, id).then(() => _persistMutationMeta(self)).then(() => {
305
- dispatch(self.dom, 'ln-data-store:deleted', { store: self._name, id, requestId });
444
+ const canonicalId = existing.id;
445
+ return _deleteRecord(self._name, canonicalId).then(() => _persistMutationMeta(self, -1)).then(() => {
446
+ dispatch(self.dom, 'ln-data-store:deleted', { store: self._name, id: canonicalId, requestId });
306
447
  });
307
448
  });
308
449
  }
@@ -316,7 +457,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
316
457
  return Promise.all(ids.map(id => _getRecord(self._name, id))).then(records => {
317
458
  const savedIds = records.filter(Boolean).map(r => r.id);
318
459
 
319
- return _deleteBulk(self._name, savedIds).then(() => _persistMutationMeta(self)).then(() => {
460
+ return _deleteBulk(self._name, savedIds).then(() => _persistMutationMeta(self, -savedIds.length)).then(() => {
320
461
  dispatch(self.dom, 'ln-data-store:deleted', { store: self._name, ids: savedIds, requestId });
321
462
  });
322
463
  });
@@ -347,6 +488,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
347
488
 
348
489
  if (self.hasCache) {
349
490
  self.isLoaded = true;
491
+ self.canServe = true;
350
492
  dispatch(self.dom, 'ln-data-store:ready', { store: self._name, count: self.totalCount, source: 'cache' });
351
493
  }
352
494
 
@@ -368,6 +510,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
368
510
  }).catch(error => {
369
511
  self.isInitialized = true;
370
512
  self.isLoaded = false;
513
+ self.canServe = false;
371
514
  self.hasCache = false;
372
515
  self.isSyncing = false;
373
516
  self.initializationError = error;
@@ -412,7 +555,14 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
412
555
  return new Promise((resolve, reject) => {
413
556
  const tx = db.transaction(storeName, 'readwrite');
414
557
  const store = tx.objectStore(storeName);
415
- ids.forEach(id => store.delete(id));
558
+ ids.forEach(id => {
559
+ store.delete(id);
560
+ if (typeof id === 'string' && id.trim() !== '' && !isNaN(Number(id))) {
561
+ store.delete(Number(id));
562
+ } else if (typeof id === 'number') {
563
+ store.delete(String(id));
564
+ }
565
+ });
416
566
  tx.oncomplete = () => resolve();
417
567
  tx.onerror = () => reject(tx.error);
418
568
  });
@@ -434,104 +584,182 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
434
584
  }));
435
585
  }
436
586
 
437
- // ─── Query Engine (In-Memory over Cache) ───────────────
438
-
439
587
  const _collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
440
588
 
441
- function _sort(records, sort) {
442
- if (!sort || !sort.field) return records;
443
- const { field, direction } = sort;
444
- const desc = direction === 'desc';
445
-
446
- return [...records].sort((a, b) => {
447
- const va = a[field];
448
- const vb = b[field];
449
-
450
- if (va == null && vb == null) return 0;
451
- if (va == null) return desc ? 1 : -1;
452
- if (vb == null) return desc ? -1 : 1;
453
-
454
- const result = (typeof va === 'string' && typeof vb === 'string')
455
- ? _collator.compare(va, vb)
456
- : (va < vb ? -1 : va > vb ? 1 : 0);
457
-
458
- return desc ? -result : result;
459
- });
589
+ function _filterKeys(filters) {
590
+ if (!filters) return [];
591
+ return Object.keys(filters).filter(k => Array.isArray(filters[k]) && filters[k].length > 0);
460
592
  }
461
593
 
462
- function _filter(records, filters) {
463
- if (!filters) return records;
464
- const keys = Object.keys(filters).filter(k => Array.isArray(filters[k]) && filters[k].length > 0);
465
- if (!keys.length) return records;
594
+ function _matchesFilters(record, keys, filters) {
595
+ return keys.every(field => filters[field].map(String).includes(String(record[field])));
596
+ }
466
597
 
467
- return records.filter(record =>
468
- keys.every(field => filters[field].map(String).includes(String(record[field])))
469
- );
598
+ function _tokenize(query) {
599
+ return String(query || '').toLowerCase().split(/\s+/).filter(Boolean);
470
600
  }
471
601
 
472
- function _search(records, query, searchFields) {
473
- if (!query || !searchFields || !searchFields.length) return records;
474
- const lower = query.toLowerCase();
475
- return records.filter(record =>
602
+ function _matchesTokens(record, tokens, searchFields) {
603
+ return tokens.every(token =>
476
604
  searchFields.some(field => {
477
605
  const val = record[field];
478
- return val != null && String(val).toLowerCase().includes(lower);
606
+ return val != null && String(val).toLowerCase().includes(token);
479
607
  })
480
608
  );
481
609
  }
482
610
 
483
611
  function _aggregate(records, field, fn) {
484
- if (!records.length) return 0;
485
- if (fn === 'count') return records.length;
612
+ return aggregateRecords(records, field, fn);
613
+ }
614
+
615
+ function _decorate(self, records) {
616
+ return decorateRecords(records, self.presenters && self.presenters.computed);
617
+ }
486
618
 
487
- const numbers = records.map(r => parseFloat(r[field])).filter(v => !isNaN(v));
488
- const sum = numbers.reduce((a, b) => a + b, 0);
619
+ // ─── Public CRUD & Sync APIs ───────────────────────────
489
620
 
490
- if (fn === 'sum') return sum;
491
- if (fn === 'avg') return numbers.length ? sum / numbers.length : 0;
492
- return 0;
621
+ // ─── Query vs Paging ───────────────────────────────────
622
+ //
623
+ // Two separate concerns, deliberately kept apart. _queryLocal answers "which
624
+ // records match, in what order" over the records this store actually holds.
625
+ // _positionalPage answers "which record sits at logical row N" using the
626
+ // server's ordering held in _windowIndex. A windowed store needs both; it must
627
+ // not let the second stand in for the first.
628
+
629
+ // Walks in primary-key order collecting matches and stops the moment the
630
+ // requested slice is full, so the cost tracks the viewport instead of the store
631
+ // (31ms vs 117ms for a 200-row slice out of 10k records).
632
+ //
633
+ // Legal only when the cursor's order already IS the output order, otherwise a
634
+ // match past the cut could belong ahead of one inside it — so an active sort
635
+ // disqualifies it. An encrypted store disqualifies it too: decryption is async
636
+ // and an await inside the cursor callback lets the transaction close.
637
+ //
638
+ // When a full pass is unavoidable the getAll path is measurably cheaper than a
639
+ // cursor (117ms vs 232ms over 10k), so that case is not routed here.
640
+ function _canScanEarly(options) {
641
+ return !options.sort && !getCryptoKey();
493
642
  }
494
643
 
495
- function _decorate(self, records) {
496
- if (!self.presenters || !self.presenters.computed) return records;
497
- const computed = self.presenters.computed;
498
- return records.map(record => {
499
- const copy = { ...record };
500
- for (const [fieldName, fn] of Object.entries(computed)) {
501
- try {
502
- copy[fieldName] = fn(record);
503
- } catch (err) {
504
- console.error(`[ln-data-store] Decorator computed field failed for ${fieldName}`, err);
505
- }
506
- }
507
- return copy;
644
+ function _scanLocal(self, options, need) {
645
+ const keys = _filterKeys(options.filters);
646
+ const tokens = options.search ? _tokenize(options.search) : [];
647
+ const searchFields = self._searchFields;
648
+ const useSearch = tokens.length > 0 && searchFields && searchFields.length > 0;
649
+
650
+ return _tx(self._name, 'readonly').then(store => {
651
+ if (!store) return [];
652
+ return new Promise((resolve, reject) => {
653
+ const found = [];
654
+ const request = store.openCursor();
655
+ request.onsuccess = () => {
656
+ const cursor = request.result;
657
+ if (!cursor || found.length >= need) {
658
+ resolve(found);
659
+ return;
660
+ }
661
+ const record = cursor.value;
662
+ const passes = (!keys.length || _matchesFilters(record, keys, options.filters))
663
+ && (!useSearch || _matchesTokens(record, tokens, searchFields));
664
+ if (passes) found.push(record);
665
+ cursor.continue();
666
+ };
667
+ request.onerror = () => reject(request.error);
668
+ });
508
669
  });
509
670
  }
510
671
 
511
- // ─── Public CRUD & Sync APIs ───────────────────────────
672
+ function _queryLocal(self, records, options) {
673
+ return queryRecords(records, options, self._searchFields, _collator);
674
+ }
512
675
 
513
- _component.prototype.getAll = function (options = {}) {
514
- const self = this;
515
- return _getAllRecords(self._name).then(records => {
516
- const total = records.length;
676
+ function _positionalPage(self, offset, limit) {
677
+ const ids = [];
678
+ for (let i = offset; i < offset + limit; i++) {
679
+ const id = self._windowIndex.getId(i);
680
+ ids.push(id);
681
+ }
517
682
 
518
- if (options.filters) records = _filter(records, options.filters);
519
- if (options.search) records = _search(records, options.search, self._searchFields);
683
+ const uniqueResolvedIds = Array.from(new Set(ids.filter(id => id !== undefined)));
520
684
 
521
- const filtered = records.length;
685
+ return _getMultipleRecords(self._name, uniqueResolvedIds).then(records => {
686
+ const recordMap = new Map();
687
+ for (let i = 0; i < records.length; i++) {
688
+ const rec = records[i];
689
+ if (rec) {
690
+ recordMap.set(String(rec.id), rec);
691
+ }
692
+ }
693
+ const data = [];
694
+ for (let i = 0; i < ids.length; i++) {
695
+ const id = ids[i];
696
+ if (id === undefined) {
697
+ data.push(null);
698
+ } else {
699
+ const rec = recordMap.get(String(id));
700
+ data.push(rec || null);
701
+ }
702
+ }
703
+ return {
704
+ data: _decorate(self, data),
705
+ total: self._windowIndex.grandTotal,
706
+ filtered: self._windowIndex.logicalTotal,
707
+ offset: offset,
708
+ queryGen: self._windowIndex.queryGen
709
+ };
710
+ });
711
+ }
522
712
 
523
- if (options.sort) records = _sort(records, options.sort);
713
+ _component.prototype.getAll = function (options = {}) {
714
+ const self = this;
715
+ if (self._windowIndex) {
716
+ const offset = options.offset || 0;
717
+ const limit = options.limit || 200;
718
+ self._windowIndex.ensure(offset, offset + limit, options);
719
+
720
+ // The index holds no ordering for this query — it was reset the moment
721
+ // the query changed. Until the server's first page lands the positions
722
+ // are ours to assign, so the query is answered from the records already
723
+ // held and flagged provisional; the server's answer supersedes it at the
724
+ // next generation. Once the index HAS loaded its ordering is authoritative
725
+ // and a page still missing stays a placeholder — splicing local records
726
+ // into server positions would put the wrong record on the row.
727
+ // Told to leave queries to the server: report the window as unresolved and
728
+ // let the view hold the previous generation until the server answers. The
729
+ // positional page below stays available either way — those rows are the
730
+ // server's own answer, only materialised from cache.
731
+ if (!self._windowIndex.hasLoaded && !self.noLocalQuery) {
732
+ const need = offset + limit;
733
+ // Rows only, never totals — see window-cache.ingest. Nothing to show
734
+ // (empty store, or nothing matched locally) is not an answer either:
735
+ // the positional page reports the window as unresolved and the view
736
+ // keeps the previous generation until the server settles it.
737
+ const provisional = records => records.length
738
+ ? {
739
+ data: _decorate(self, records),
740
+ offset: offset,
741
+ queryGen: self._windowIndex.queryGen,
742
+ provisional: true
743
+ }
744
+ : _positionalPage(self, offset, limit);
524
745
 
525
- if (options.offset || options.limit) {
526
- const offset = options.offset || 0;
527
- const limit = options.limit || records.length;
528
- records = records.slice(offset, offset + limit);
746
+ if (_canScanEarly(options)) {
747
+ return _scanLocal(self, options, need).then(matches =>
748
+ provisional(matches.slice(offset, need)));
749
+ }
750
+ return _getAllRecords(self._name).then(records =>
751
+ provisional(_queryLocal(self, records, options).records));
529
752
  }
530
753
 
754
+ return _positionalPage(self, offset, limit);
755
+ }
756
+
757
+ return _getAllRecords(self._name).then(records => {
758
+ const r = _queryLocal(self, records, options);
531
759
  return {
532
- data: _decorate(self, records),
533
- total,
534
- filtered
760
+ data: _decorate(self, r.records),
761
+ total: r.total,
762
+ filtered: r.filtered
535
763
  };
536
764
  });
537
765
  };
@@ -541,9 +769,12 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
541
769
  };
542
770
 
543
771
  _component.prototype.count = function (filters) {
544
- return filters
545
- ? _getAllRecords(this._name).then(records => _filter(records, filters).length)
546
- : _countRecords(this._name);
772
+ const hasFilters = filters && Object.keys(filters).length > 0;
773
+ if (!hasFilters) {
774
+ if (this.totalCount != null) return Promise.resolve(this.totalCount);
775
+ return _countRecords(this._name);
776
+ }
777
+ return _getAllRecords(this._name).then(records => filterRecords(records, filters).length);
547
778
  };
548
779
 
549
780
  _component.prototype.aggregate = function (field, fn) {
@@ -559,12 +790,25 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
559
790
  _component.prototype.applySync = function (upsertedRecords, deletedIds, syncedAt, meta) {
560
791
  meta = meta || {};
561
792
  const self = this;
793
+ if (self._windowIndex && meta.queryGen != null && meta.queryGen !== self._windowIndex.queryGen) {
794
+ return Promise.resolve();
795
+ }
796
+
797
+ const hasChanges = upsertedRecords.length > 0 || deletedIds.length > 0;
562
798
 
563
799
  let chain = Promise.resolve();
564
800
  if (upsertedRecords.length > 0) chain = chain.then(() => _putBulk(self._name, upsertedRecords));
565
801
  if (deletedIds.length > 0) chain = chain.then(() => _deleteBulk(self._name, deletedIds));
566
802
 
567
- return chain.then(() => _countRecords(self._name)).then(count => {
803
+ return chain.then(() => {
804
+ if (self._windowIndex && (meta.offset != null || meta.total != null)) {
805
+ const offset = meta.offset != null ? meta.offset : 0;
806
+ const ids = upsertedRecords.map(r => r.id);
807
+ // Residency is the index: what the window pushed out stops being held.
808
+ const evicted = self._windowIndex.ingest(offset, ids, meta.total, meta.filtered, meta.queryGen);
809
+ if (evicted && evicted.length) return _deleteBulk(self._name, evicted);
810
+ }
811
+ }).then(() => _countRecords(self._name)).then(count => {
568
812
  self.totalCount = meta.total !== undefined ? meta.total : count;
569
813
  self.hasCache = true;
570
814
  return _setMeta(self._name, {
@@ -576,6 +820,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
576
820
  }).then(() => {
577
821
  const isInitialLoad = !self.isLoaded;
578
822
  self.isLoaded = true;
823
+ self.canServe = true;
579
824
  self.isSyncing = false;
580
825
  self.lastSyncedAt = syncedAt;
581
826
 
@@ -608,8 +853,10 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
608
853
 
609
854
  return chain.then(() => _countRecords(self._name)).then(count => {
610
855
  self.totalCount = meta.total !== undefined ? meta.total : count;
611
- // record_count/has_cache stay untouched — a page fetch is not an
856
+ // record_count/has_cache/isLoaded stay untouched — a page fetch is not an
612
857
  // authoritative cache; it would corrupt _isStale/storeInitialized sync gating.
858
+ // It does leave records behind, so the store can serve reads from here on.
859
+ if (upsertedRecords.length > 0) self.canServe = true;
613
860
  return _decorate(self, upsertedRecords);
614
861
  }).catch(err => {
615
862
  console.error('[ln-data-store] applyQuery failed:', err);
@@ -641,17 +888,27 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
641
888
  };
642
889
 
643
890
  _component.prototype.destroy = function () {
891
+ if (this._windowIndex) {
892
+ this._windowIndex.clear();
893
+ this._windowIndex = null;
894
+ this.windowed = false;
895
+ }
644
896
  if (this._handlers) {
645
897
  for (const [event, fn] of Object.entries(this._handlers)) {
646
898
  this.dom.removeEventListener(`ln-data-store:request-${event}`, fn);
647
899
  }
648
900
  this._handlers = null;
649
901
  }
902
+ if (this._queryHandlers) {
903
+ for (const [event, fn] of Object.entries(this._queryHandlers)) {
904
+ this.dom.removeEventListener(event, fn);
905
+ }
906
+ this._queryHandlers = null;
907
+ }
650
908
 
651
909
  delete _stores[this._name];
652
910
 
653
911
  delete this.dom[DOM_ATTRIBUTE];
654
- dispatch(this.dom, 'ln-data-store:destroyed', { store: this._name });
655
912
  };
656
913
 
657
914
  // ─── clearAll (global) ─────────────────────────────────
@@ -669,6 +926,7 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
669
926
  }).then(() => {
670
927
  Object.values(_stores).forEach(inst => {
671
928
  inst.isLoaded = false;
929
+ inst.canServe = false;
672
930
  inst.isInitialized = false;
673
931
  inst.initializationError = null;
674
932
  inst.hasCache = false;
@@ -679,9 +937,53 @@ import { registerComponent, dispatch, setCryptoKey, getCryptoKey, encryptData, d
679
937
  });
680
938
  }
681
939
 
940
+ function _emitQueryChanged(self) {
941
+ if (self._windowIndex) {
942
+ self._windowIndex.reset();
943
+ }
944
+ dispatch(self.dom, 'ln-data-store:query-changed', {
945
+ store: self._name,
946
+ query: {
947
+ filters: Object.assign({}, self.query.filters),
948
+ search: self.query.search,
949
+ sort: self.query.sort ? Object.assign({}, self.query.sort) : null
950
+ }
951
+ });
952
+ }
953
+
682
954
  // ─── Registration ──────────────────────────────────────
683
955
 
684
- registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-data-store');
956
+ const FROZEN_ATTR = 'data-ln-data-store-frozen';
957
+
958
+ // The IndexedDB schema and the store's registered name are fixed at open
959
+ // time: createIndex is only legal inside a versionchange transaction
960
+ // (see onupgradeneeded, :85-94). A post-init edit is recorded on the host
961
+ // for the dev stylesheet to surface; nothing is applied.
962
+ function _markFrozen(el, attrName) {
963
+ el.setAttribute(FROZEN_ATTR, attrName);
964
+ }
965
+
966
+ // Shrinking the window drops positions; the records behind them stop being
967
+ // held, exactly as on ingest (:757-758), so they leave IndexedDB too.
968
+ function _applyWindowSize(el) {
969
+ const inst = el[DOM_ATTRIBUTE];
970
+ if (!inst._windowIndex) return;
971
+ const evicted = inst._windowIndex.configure({ windowSize: inst._windowSize });
972
+ if (evicted.length) {
973
+ _deleteBulk(inst._name, evicted).catch(err => {
974
+ console.error('[ln-data-store] window shrink eviction failed:', err);
975
+ });
976
+ }
977
+ }
978
+
979
+ function _applyWindowPageSize(el) {
980
+ const inst = el[DOM_ATTRIBUTE];
981
+ if (inst._windowIndex) inst._windowIndex.configure({ pageSize: inst._windowPageSize });
982
+ }
983
+
984
+ registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-data-store', {
985
+ attributes: ATTRIBUTES
986
+ });
685
987
 
686
988
  window[DOM_ATTRIBUTE].clearAll = _clearAll;
687
989
  window[DOM_ATTRIBUTE].init = window[DOM_ATTRIBUTE];