@livenetworks/ashlar 1.6.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (560) hide show
  1. package/LICENSE +641 -0
  2. package/README.md +202 -86
  3. package/{js → components}/COMPONENTS.md +1116 -1108
  4. package/{js → components}/index.js +81 -58
  5. package/{js → components}/ln-accordion/README.md +7 -6
  6. package/components/ln-accordion/ln-accordion-dev.scss +8 -0
  7. package/components/ln-accordion/ln-accordion.js +1 -0
  8. package/components/ln-accordion/ln-accordion.schema.json +30 -0
  9. package/components/ln-accordion/ln-accordion.scss +8 -0
  10. package/{js → components}/ln-accordion/src/ln-accordion.js +8 -2
  11. package/{js → components}/ln-ajax/README.md +171 -160
  12. package/components/ln-ajax/ln-ajax-dev.scss +8 -0
  13. package/components/ln-ajax/ln-ajax.js +1 -0
  14. package/components/ln-ajax/ln-ajax.schema.json +30 -0
  15. package/{js → components}/ln-ajax/src/ln-ajax.js +65 -30
  16. package/{js → components}/ln-api-connector/README.md +27 -5
  17. package/components/ln-api-connector/ln-api-connector.js +1 -0
  18. package/components/ln-api-connector/ln-api-connector.schema.json +96 -0
  19. package/components/ln-api-connector/src/connector-core.js +97 -0
  20. package/components/ln-api-connector/src/ln-api-connector.js +447 -0
  21. package/{js → components}/ln-api-queue/README.md +12 -9
  22. package/components/ln-api-queue/ln-api-queue.js +1 -0
  23. package/components/ln-api-queue/ln-api-queue.schema.json +34 -0
  24. package/{js → components}/ln-api-queue/src/ln-api-queue.js +33 -14
  25. package/{js → components}/ln-api-queue/src/queue-storage.js +7 -3
  26. package/{js → components}/ln-autoresize/README.md +129 -127
  27. package/components/ln-autoresize/ln-autoresize-dev.scss +8 -0
  28. package/components/ln-autoresize/ln-autoresize.js +1 -0
  29. package/components/ln-autoresize/ln-autoresize.schema.json +22 -0
  30. package/{js → components}/ln-autoresize/src/ln-autoresize.js +8 -1
  31. package/{js → components}/ln-autosave/README.md +127 -124
  32. package/components/ln-autosave/ln-autosave-dev.scss +13 -0
  33. package/components/ln-autosave/ln-autosave.js +1 -0
  34. package/components/ln-autosave/ln-autosave.schema.json +48 -0
  35. package/components/ln-autosave/src/autosave-model.js +34 -0
  36. package/{js → components}/ln-autosave/src/ln-autosave.js +65 -58
  37. package/components/ln-chart/README.md +145 -0
  38. package/components/ln-chart/ln-chart-dev.scss +20 -0
  39. package/components/ln-chart/ln-chart.js +1 -0
  40. package/components/ln-chart/ln-chart.schema.json +146 -0
  41. package/components/ln-chart/ln-chart.scss +8 -0
  42. package/components/ln-chart/src/chart-model.js +154 -0
  43. package/components/ln-chart/src/ln-chart.js +176 -0
  44. package/{js → components}/ln-circular-progress/README.md +15 -14
  45. package/components/ln-circular-progress/ln-circular-progress-dev.scss +8 -0
  46. package/components/ln-circular-progress/ln-circular-progress.js +1 -0
  47. package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -0
  48. package/{js → components}/ln-circular-progress/src/ln-circular-progress.js +32 -50
  49. package/components/ln-confirm/README.md +216 -0
  50. package/components/ln-confirm/ln-confirm-dev.scss +24 -0
  51. package/components/ln-confirm/ln-confirm.js +1 -0
  52. package/components/ln-confirm/ln-confirm.schema.json +66 -0
  53. package/components/ln-confirm/ln-confirm.scss +24 -0
  54. package/{js → components}/ln-confirm/src/ln-confirm.js +180 -167
  55. package/{js → components}/ln-core/README.md +374 -149
  56. package/components/ln-core/attrs.js +273 -0
  57. package/components/ln-core/compare.js +40 -0
  58. package/components/ln-core/crypto.js +265 -0
  59. package/components/ln-core/date.js +50 -0
  60. package/components/ln-core/dom.js +115 -0
  61. package/components/ln-core/events.js +122 -0
  62. package/components/ln-core/form.js +136 -0
  63. package/{js → components}/ln-core/hash.js +149 -92
  64. package/components/ln-core/helpers.js +33 -0
  65. package/components/ln-core/http.js +48 -0
  66. package/components/ln-core/index.js +11 -0
  67. package/components/ln-core/lifecycle.js +403 -0
  68. package/components/ln-core/ln-core.schema.json +109 -0
  69. package/components/ln-core/locale.js +55 -0
  70. package/components/ln-core/matching.js +78 -0
  71. package/components/ln-core/number.js +125 -0
  72. package/components/ln-core/progress.js +30 -0
  73. package/components/ln-core/template.js +206 -0
  74. package/{js → components}/ln-core/window-cache.js +247 -213
  75. package/{js → components}/ln-couchdb-connector/README.md +7 -5
  76. package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
  77. package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -0
  78. package/{js → components}/ln-couchdb-connector/src/ln-couchdb-connector.js +29 -43
  79. package/{js → components}/ln-data-coordinator/README.md +109 -73
  80. package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -0
  81. package/components/ln-data-coordinator/ln-data-coordinator.js +1 -0
  82. package/components/ln-data-coordinator/ln-data-coordinator.schema.json +196 -0
  83. package/components/ln-data-coordinator/src/data-read-policy.js +41 -0
  84. package/{js → components}/ln-data-coordinator/src/ln-data-coordinator.js +411 -154
  85. package/{js → components}/ln-data-coordinator/src/mutation-receipts.js +0 -5
  86. package/{js → components}/ln-data-store/README.md +42 -17
  87. package/components/ln-data-store/ln-data-store-dev.scss +13 -0
  88. package/components/ln-data-store/ln-data-store.js +1 -0
  89. package/components/ln-data-store/ln-data-store.schema.json +84 -0
  90. package/components/ln-data-store/src/data-store-model.js +155 -0
  91. package/{js → components}/ln-data-store/src/ln-data-store.js +407 -105
  92. package/components/ln-data-store/src/window-index.js +119 -0
  93. package/{js → components}/ln-date/README.md +17 -7
  94. package/{js → components}/ln-date/ln-date-dev.scss +14 -14
  95. package/components/ln-date/ln-date.js +1 -0
  96. package/components/ln-date/ln-date.schema.json +92 -0
  97. package/components/ln-date/src/date-model.js +186 -0
  98. package/components/ln-date/src/ln-date.js +486 -0
  99. package/components/ln-debug/README.md +132 -0
  100. package/components/ln-debug/ln-debug.js +1 -0
  101. package/components/ln-debug/ln-debug.schema.json +28 -0
  102. package/components/ln-debug/src/console-sink.js +19 -0
  103. package/components/ln-debug/src/debug-verifier.js +331 -0
  104. package/components/ln-debug/src/gate.js +95 -0
  105. package/components/ln-debug/src/generated-attributes.js +299 -0
  106. package/components/ln-debug/src/ln-debug.js +60 -0
  107. package/{js → components}/ln-dropdown/README.md +150 -140
  108. package/components/ln-dropdown/ln-dropdown-dev.scss +13 -0
  109. package/components/ln-dropdown/ln-dropdown.js +1 -0
  110. package/components/ln-dropdown/ln-dropdown.schema.json +90 -0
  111. package/components/ln-dropdown/ln-dropdown.scss +18 -0
  112. package/{js → components}/ln-dropdown/src/ln-dropdown.js +114 -11
  113. package/{js → components}/ln-editor/README.md +11 -9
  114. package/components/ln-editor/ln-editor-dev.scss +18 -0
  115. package/components/ln-editor/ln-editor.js +1 -0
  116. package/components/ln-editor/ln-editor.schema.json +58 -0
  117. package/components/ln-editor/ln-editor.scss +13 -0
  118. package/{js → components}/ln-editor/src/ln-editor.js +59 -11
  119. package/{js → components}/ln-external-links/README.md +10 -8
  120. package/components/ln-external-links/ln-external-links.js +1 -0
  121. package/components/ln-external-links/ln-external-links.schema.json +18 -0
  122. package/{js → components}/ln-external-links/src/ln-external-links.js +13 -11
  123. package/{js → components}/ln-fill/README.md +6 -8
  124. package/components/ln-fill/ln-fill.js +1 -0
  125. package/components/ln-fill/ln-fill.schema.json +23 -0
  126. package/{js → components}/ln-fill/src/ln-fill.js +7 -1
  127. package/components/ln-filter/README.md +131 -0
  128. package/components/ln-filter/ln-filter-dev.scss +13 -0
  129. package/components/ln-filter/ln-filter.js +1 -0
  130. package/components/ln-filter/ln-filter.schema.json +153 -0
  131. package/components/ln-filter/src/filter-model.js +185 -0
  132. package/components/ln-filter/src/ln-filter.js +435 -0
  133. package/{js → components}/ln-form/README.md +260 -264
  134. package/components/ln-form/ln-form-dev.scss +8 -0
  135. package/components/ln-form/ln-form.js +1 -0
  136. package/components/ln-form/ln-form.schema.json +45 -0
  137. package/{js → components}/ln-form/src/ln-form.js +107 -99
  138. package/{js → components}/ln-http/README.md +11 -6
  139. package/components/ln-http/ln-http.js +1 -0
  140. package/components/ln-http/ln-http.schema.json +6 -0
  141. package/components/ln-http/src/http-core.js +51 -0
  142. package/{js → components}/ln-http/src/ln-http.js +28 -33
  143. package/{js → components}/ln-icon/README.md +16 -9
  144. package/components/ln-icon/ln-icon.schema.json +6 -0
  145. package/components/ln-include/README.md +75 -0
  146. package/components/ln-include/ln-include-dev.scss +13 -0
  147. package/components/ln-include/ln-include.js +1 -0
  148. package/components/ln-include/ln-include.schema.json +23 -0
  149. package/components/ln-include/src/ln-include.js +111 -0
  150. package/components/ln-key/README.md +130 -0
  151. package/components/ln-key/ln-key-dev.scss +18 -0
  152. package/components/ln-key/ln-key.js +1 -0
  153. package/components/ln-key/ln-key.schema.json +56 -0
  154. package/components/ln-key/src/key-model.js +146 -0
  155. package/components/ln-key/src/ln-key.js +201 -0
  156. package/{js → components}/ln-link/README.md +7 -9
  157. package/components/ln-link/ln-link-dev.scss +8 -0
  158. package/components/ln-link/ln-link.js +1 -0
  159. package/components/ln-link/ln-link.schema.json +22 -0
  160. package/{js → components}/ln-link/src/ln-link.js +16 -11
  161. package/components/ln-list/README.md +152 -0
  162. package/components/ln-list/ln-list-dev.scss +8 -0
  163. package/components/ln-list/ln-list.js +1 -0
  164. package/components/ln-list/ln-list.schema.json +166 -0
  165. package/components/ln-list/ln-list.scss +25 -0
  166. package/{js → components}/ln-list/src/ln-list.js +1301 -1216
  167. package/{js → components}/ln-modal/README.md +13 -10
  168. package/components/ln-modal/ln-modal-dev.scss +18 -0
  169. package/components/ln-modal/ln-modal.js +1 -0
  170. package/components/ln-modal/ln-modal.schema.json +54 -0
  171. package/components/ln-modal/ln-modal.scss +51 -0
  172. package/{js → components}/ln-modal/src/ln-modal.js +164 -137
  173. package/{js → components}/ln-nav/README.md +11 -11
  174. package/components/ln-nav/ln-nav.js +1 -0
  175. package/components/ln-nav/ln-nav.schema.json +25 -0
  176. package/{js → components}/ln-nav/src/ln-nav.js +25 -14
  177. package/components/ln-number/README.md +205 -0
  178. package/{js → components}/ln-number/ln-number-dev.scss +13 -13
  179. package/components/ln-number/ln-number.js +1 -0
  180. package/components/ln-number/ln-number.schema.json +63 -0
  181. package/components/ln-number/src/ln-number.js +400 -0
  182. package/components/ln-number/src/number-model.js +31 -0
  183. package/components/ln-obfuscator/README.md +60 -0
  184. package/components/ln-obfuscator/ln-obfuscator.js +1 -0
  185. package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -0
  186. package/components/ln-obfuscator/src/ln-obfuscator.js +159 -0
  187. package/components/ln-obfuscator/src/obfuscator-model.js +250 -0
  188. package/{js → components}/ln-options/README.md +3 -1
  189. package/components/ln-options/ln-options-dev.scss +13 -0
  190. package/components/ln-options/ln-options.js +1 -0
  191. package/components/ln-options/ln-options.schema.json +41 -0
  192. package/{js → components}/ln-options/src/ln-options.js +13 -5
  193. package/components/ln-persist/README.md +151 -0
  194. package/components/ln-persist/ln-persist.js +1 -0
  195. package/components/ln-persist/ln-persist.schema.json +28 -0
  196. package/components/ln-persist/src/ln-persist.js +83 -0
  197. package/components/ln-picklist/README.md +230 -0
  198. package/components/ln-picklist/ln-picklist-dev.scss +22 -0
  199. package/components/ln-picklist/ln-picklist.js +1 -0
  200. package/components/ln-picklist/ln-picklist.schema.json +49 -0
  201. package/components/ln-picklist/src/ln-picklist.js +228 -0
  202. package/{js → components}/ln-popover/README.md +164 -162
  203. package/components/ln-popover/ln-popover-dev.scss +13 -0
  204. package/components/ln-popover/ln-popover.js +1 -0
  205. package/components/ln-popover/ln-popover.schema.json +82 -0
  206. package/components/ln-popover/ln-popover.scss +18 -0
  207. package/{js → components}/ln-popover/src/ln-popover.js +42 -36
  208. package/{js → components}/ln-progress/README.md +410 -413
  209. package/components/ln-progress/ln-progress-dev.scss +8 -0
  210. package/components/ln-progress/ln-progress.js +1 -0
  211. package/components/ln-progress/ln-progress.schema.json +40 -0
  212. package/components/ln-progress/src/ln-progress.js +91 -0
  213. package/components/ln-progress/src/progress-model.js +20 -0
  214. package/{js → components}/ln-router/README.md +443 -432
  215. package/components/ln-router/ln-router-dev.scss +13 -0
  216. package/components/ln-router/ln-router.js +1 -0
  217. package/components/ln-router/ln-router.schema.json +68 -0
  218. package/{js → components}/ln-router/src/ln-router.js +585 -539
  219. package/components/ln-router/src/router-model.js +50 -0
  220. package/components/ln-scroll/README.md +45 -0
  221. package/components/ln-scroll/ln-scroll.js +1 -0
  222. package/components/ln-scroll/ln-scroll.schema.json +85 -0
  223. package/components/ln-scroll/src/ln-scroll.js +150 -0
  224. package/components/ln-search/README.md +188 -0
  225. package/components/ln-search/ln-search-dev.scss +13 -0
  226. package/components/ln-search/ln-search.js +1 -0
  227. package/components/ln-search/ln-search.schema.json +103 -0
  228. package/components/ln-search/src/ln-search.js +330 -0
  229. package/{js → components}/ln-slug/README.md +6 -3
  230. package/components/ln-slug/ln-slug-dev.scss +18 -0
  231. package/components/ln-slug/ln-slug.js +1 -0
  232. package/components/ln-slug/ln-slug.schema.json +23 -0
  233. package/{js → components}/ln-slug/src/ln-slug.js +20 -13
  234. package/components/ln-slug/src/slug-model.js +21 -0
  235. package/{js → components}/ln-sort/README.md +178 -170
  236. package/{js → components}/ln-sort/ln-sort-dev.scss +8 -8
  237. package/components/ln-sort/ln-sort.js +1 -0
  238. package/components/ln-sort/ln-sort.schema.json +104 -0
  239. package/components/ln-sort/src/ln-sort.js +321 -0
  240. package/components/ln-sort/src/sort-model.js +117 -0
  241. package/{js → components}/ln-sortable/README.md +7 -11
  242. package/components/ln-sortable/ln-sortable-dev.scss +13 -0
  243. package/components/ln-sortable/ln-sortable.js +1 -0
  244. package/components/ln-sortable/ln-sortable.schema.json +36 -0
  245. package/{js → components}/ln-sortable/src/ln-sortable.js +8 -13
  246. package/{js → components}/ln-stat/README.md +3 -1
  247. package/components/ln-stat/ln-stat-dev.scss +8 -0
  248. package/components/ln-stat/ln-stat.js +1 -0
  249. package/components/ln-stat/ln-stat.schema.json +32 -0
  250. package/{js → components}/ln-stat/src/ln-stat.js +14 -18
  251. package/components/ln-stat/src/stat-model.js +28 -0
  252. package/{js → components}/ln-table/README.md +37 -24
  253. package/{js → components}/ln-table/ln-table-dev.scss +17 -17
  254. package/components/ln-table/ln-table.js +1 -0
  255. package/components/ln-table/ln-table.schema.json +211 -0
  256. package/components/ln-table/ln-table.scss +15 -0
  257. package/{js → components}/ln-table/src/ln-table.js +1365 -1493
  258. package/components/ln-table/src/table-model.js +98 -0
  259. package/components/ln-table-coordinator/README.md +61 -0
  260. package/components/ln-table-coordinator/ln-table-coordinator.js +1 -0
  261. package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -0
  262. package/components/ln-table-coordinator/src/ln-table-coordinator.js +193 -0
  263. package/{js → components}/ln-tabs/README.md +32 -14
  264. package/components/ln-tabs/ln-tabs-dev.scss +24 -0
  265. package/components/ln-tabs/ln-tabs.js +1 -0
  266. package/components/ln-tabs/ln-tabs.schema.json +75 -0
  267. package/components/ln-tabs/ln-tabs.scss +8 -0
  268. package/components/ln-tabs/src/ln-tabs.js +207 -0
  269. package/components/ln-tabs/src/tabs-model.js +82 -0
  270. package/{js → components}/ln-time/README.md +96 -95
  271. package/components/ln-time/ln-time-dev.scss +13 -0
  272. package/components/ln-time/ln-time.js +1 -0
  273. package/components/ln-time/ln-time.schema.json +38 -0
  274. package/{js → components}/ln-time/src/ln-time.js +206 -223
  275. package/components/ln-time/src/time-model.js +64 -0
  276. package/{js → components}/ln-toast/README.md +23 -5
  277. package/components/ln-toast/ln-toast-dev.scss +8 -0
  278. package/components/ln-toast/ln-toast.js +1 -0
  279. package/components/ln-toast/ln-toast.schema.json +65 -0
  280. package/components/ln-toast/ln-toast.scss +59 -0
  281. package/{js → components}/ln-toast/src/ln-toast.js +233 -232
  282. package/{js → components}/ln-toggle/README.md +198 -196
  283. package/{js → components}/ln-toggle/ln-toggle-dev.scss +13 -13
  284. package/components/ln-toggle/ln-toggle.js +1 -0
  285. package/components/ln-toggle/ln-toggle.schema.json +52 -0
  286. package/components/ln-toggle/ln-toggle.scss +37 -0
  287. package/{js → components}/ln-toggle/src/ln-toggle.js +61 -46
  288. package/{js → components}/ln-tooltip/README.md +6 -6
  289. package/{js → components}/ln-tooltip/ln-tooltip-dev.scss +9 -9
  290. package/components/ln-tooltip/ln-tooltip.js +1 -0
  291. package/components/ln-tooltip/ln-tooltip.schema.json +86 -0
  292. package/components/ln-tooltip/ln-tooltip.scss +9 -0
  293. package/{js → components}/ln-tooltip/src/ln-tooltip.js +14 -3
  294. package/{js → components}/ln-translations/README.md +3 -1
  295. package/components/ln-translations/ln-translations-dev.scss +13 -0
  296. package/components/ln-translations/ln-translations.js +1 -0
  297. package/components/ln-translations/ln-translations.schema.json +120 -0
  298. package/{js → components}/ln-translations/src/ln-translations.js +25 -10
  299. package/components/ln-ui-coordinator/README.md +101 -0
  300. package/components/ln-ui-coordinator/ln-ui-coordinator-dev.scss +8 -0
  301. package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -0
  302. package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +60 -0
  303. package/{js/ln-modal-coordinator/src/ln-modal-coordinator.js → components/ln-ui-coordinator/src/ln-ui-coordinator.js} +403 -345
  304. package/components/ln-upload/README.md +133 -0
  305. package/components/ln-upload/ln-upload-dev.scss +18 -0
  306. package/components/ln-upload/ln-upload.js +1 -0
  307. package/components/ln-upload/ln-upload.schema.json +193 -0
  308. package/components/ln-upload/ln-upload.scss +20 -0
  309. package/components/ln-upload/src/ln-upload.js +652 -0
  310. package/components/ln-upload/src/upload-model.js +78 -0
  311. package/{js → components}/ln-validate/README.md +182 -180
  312. package/{js → components}/ln-validate/ln-validate-dev.scss +15 -15
  313. package/components/ln-validate/ln-validate.js +1 -0
  314. package/components/ln-validate/ln-validate.schema.json +50 -0
  315. package/components/ln-validate/ln-validate.scss +7 -0
  316. package/{js → components}/ln-validate/src/ln-validate.js +23 -45
  317. package/components/ln-validate/src/validate-model.js +64 -0
  318. package/components/ln-websocket-connector/README.md +166 -0
  319. package/components/ln-websocket-connector/ln-websocket-connector.js +1 -0
  320. package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -0
  321. package/components/ln-websocket-connector/src/ln-websocket-connector.js +279 -0
  322. package/ln-ashlar.html-data.json +1796 -0
  323. package/package.json +84 -61
  324. package/{scss → theme}/base/_global.scss +1 -2
  325. package/{scss → theme}/base/_reset.scss +1 -1
  326. package/{scss → theme}/base/_typography.scss +2 -0
  327. package/theme/brand.css +73 -0
  328. package/{scss → theme}/components/_app-shell.scss +8 -0
  329. package/theme/components/_button.scss +24 -0
  330. package/theme/components/_chart.scss +5 -0
  331. package/theme/components/_confirm.scss +6 -0
  332. package/{scss → theme}/components/_date.scss +30 -22
  333. package/{scss → theme}/components/_dropdown.scss +6 -1
  334. package/theme/components/_form.scss +140 -0
  335. package/{scss → theme}/components/_layout.scss +6 -0
  336. package/{scss → theme}/components/_ln-table.scss +1 -6
  337. package/theme/components/_picklist.scss +3 -0
  338. package/{scss → theme}/components/_sort.scss +10 -10
  339. package/theme/components/_status-badge.scss +6 -0
  340. package/{scss → theme}/components/_table.scss +16 -0
  341. package/{scss → theme}/components/_tabs.scss +0 -4
  342. package/theme/components/_toast.scss +48 -0
  343. package/{scss → theme}/components/_toggle.scss +1 -1
  344. package/theme/components/_upload.scss +45 -0
  345. package/{scss → theme}/config/_breakpoints.scss +1 -1
  346. package/theme/config/_contrast.scss +128 -0
  347. package/{scss → theme}/config/_density.scss +191 -205
  348. package/theme/config/_palette.scss +274 -0
  349. package/theme/config/_theme.scss +293 -0
  350. package/{scss → theme}/config/_tokens.scss +285 -441
  351. package/{scss → theme}/config/mixins/_accordion.scss +1 -1
  352. package/{scss → theme}/config/mixins/_alert.scss +1 -0
  353. package/{scss → theme}/config/mixins/_app-shell.scss +4 -2
  354. package/{scss → theme}/config/mixins/_borders.scss +2 -0
  355. package/theme/config/mixins/_btn.scss +175 -0
  356. package/{scss → theme}/config/mixins/_card.scss +55 -46
  357. package/theme/config/mixins/_chart.scss +82 -0
  358. package/{scss → theme}/config/mixins/_collapsible.scss +2 -1
  359. package/{scss → theme}/config/mixins/_colors.scss +8 -14
  360. package/{scss → theme}/config/mixins/_diagnostics.scss +48 -48
  361. package/theme/config/mixins/_dropdown.scss +169 -0
  362. package/{scss → theme}/config/mixins/_editor.scss +0 -7
  363. package/{scss → theme}/config/mixins/_filter.scss +47 -47
  364. package/{scss → theme}/config/mixins/_footer.scss +1 -1
  365. package/{scss → theme}/config/mixins/_form.scss +49 -18
  366. package/{scss → theme}/config/mixins/_index.scss +62 -61
  367. package/{scss → theme}/config/mixins/_layout.scss +6 -2
  368. package/{scss → theme}/config/mixins/_ln-table.scss +31 -10
  369. package/{scss → theme}/config/mixins/_loader.scss +1 -1
  370. package/{scss → theme}/config/mixins/_modal.scss +145 -149
  371. package/{scss → theme}/config/mixins/_motion.scss +13 -0
  372. package/{scss → theme}/config/mixins/_nav.scss +7 -7
  373. package/theme/config/mixins/_picklist.scss +66 -0
  374. package/theme/config/mixins/_popover.scss +96 -0
  375. package/{scss → theme}/config/mixins/_sidebar.scss +7 -4
  376. package/{scss → theme}/config/mixins/_sort.scss +43 -42
  377. package/{scss → theme}/config/mixins/_status-badge.scss +15 -2
  378. package/{scss → theme}/config/mixins/_table.scss +25 -14
  379. package/{scss → theme}/config/mixins/_tabs.scss +1 -1
  380. package/{scss → theme}/config/mixins/_toast.scss +174 -179
  381. package/{scss → theme}/config/mixins/_tooltip.scss +2 -2
  382. package/{scss → theme}/config/mixins/_typography.scss +16 -5
  383. package/{scss → theme}/config/mixins/_upload.scss +8 -6
  384. package/theme/ln-ashlar-core.scss +24 -0
  385. package/theme/ln-ashlar-dev.scss +66 -0
  386. package/theme/ln-ashlar-landing.scss +56 -0
  387. package/{scss/ln-ashlar.scss → theme/ln-ashlar-theme.scss} +63 -69
  388. package/theme/ln-ashlar.scss +8 -0
  389. package/theme/presentation/_bento.scss +151 -0
  390. package/theme/presentation/_cta.scss +111 -0
  391. package/theme/presentation/_effects.scss +216 -0
  392. package/theme/presentation/_features.scss +108 -0
  393. package/theme/presentation/_footer.scss +129 -0
  394. package/theme/presentation/_hero.scss +158 -0
  395. package/theme/presentation/_layout.scss +170 -0
  396. package/theme/presentation/_navbar.scss +140 -0
  397. package/theme/presentation/_pricing.scss +262 -0
  398. package/theme/presentation/_stats.scss +87 -0
  399. package/theme/presentation/_testimonials.scss +124 -0
  400. package/theme/presentation/_tokens.scss +39 -0
  401. package/theme/presentation/_typography.scss +163 -0
  402. package/{scss → theme}/utilities/_animations.scss +38 -0
  403. package/{scss → theme}/utilities/_utilities.scss +6 -0
  404. package/web-types.json +2312 -0
  405. package/js/ln-accordion/ln-accordion.js +0 -1
  406. package/js/ln-ajax/ln-ajax.js +0 -1
  407. package/js/ln-api-connector/ln-api-connector.js +0 -1
  408. package/js/ln-api-connector/src/ln-api-connector.js +0 -368
  409. package/js/ln-api-queue/ln-api-queue.js +0 -1
  410. package/js/ln-autoresize/ln-autoresize.js +0 -1
  411. package/js/ln-autosave/ln-autosave.js +0 -1
  412. package/js/ln-circular-progress/ln-circular-progress.js +0 -1
  413. package/js/ln-confirm/README.md +0 -162
  414. package/js/ln-confirm/_ln-confirm.scss +0 -24
  415. package/js/ln-confirm/ln-confirm.js +0 -1
  416. package/js/ln-core/crypto.js +0 -83
  417. package/js/ln-core/helpers.js +0 -788
  418. package/js/ln-core/index.js +0 -7
  419. package/js/ln-core/persist.js +0 -97
  420. package/js/ln-couchdb-connector/ln-couchdb-connector.js +0 -1
  421. package/js/ln-data-coordinator/ln-data-coordinator.js +0 -1
  422. package/js/ln-data-coordinator/src/data-read-policy.js +0 -18
  423. package/js/ln-data-store/ln-data-store.js +0 -1
  424. package/js/ln-date/ln-date.js +0 -1
  425. package/js/ln-date/src/ln-date.js +0 -603
  426. package/js/ln-debug/README.md +0 -58
  427. package/js/ln-debug/ln-debug.js +0 -1
  428. package/js/ln-debug/src/ln-debug.js +0 -19
  429. package/js/ln-dropdown/ln-dropdown.js +0 -1
  430. package/js/ln-dropdown/ln-dropdown.scss +0 -15
  431. package/js/ln-editor/ln-editor.js +0 -1
  432. package/js/ln-editor/ln-editor.scss +0 -43
  433. package/js/ln-external-links/ln-external-links.js +0 -1
  434. package/js/ln-fill/ln-fill.js +0 -1
  435. package/js/ln-filter/README.md +0 -189
  436. package/js/ln-filter/ln-filter-dev.scss +0 -8
  437. package/js/ln-filter/ln-filter.js +0 -1
  438. package/js/ln-filter/src/ln-filter.js +0 -419
  439. package/js/ln-form/ln-form.js +0 -1
  440. package/js/ln-http/ln-http.js +0 -1
  441. package/js/ln-link/ln-link.js +0 -1
  442. package/js/ln-list/README.md +0 -129
  443. package/js/ln-list/ln-list.js +0 -1
  444. package/js/ln-list/ln-list.scss +0 -28
  445. package/js/ln-modal/ln-modal-dev.scss +0 -13
  446. package/js/ln-modal/ln-modal.js +0 -1
  447. package/js/ln-modal/ln-modal.scss +0 -35
  448. package/js/ln-modal-coordinator/README.md +0 -99
  449. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +0 -8
  450. package/js/ln-modal-coordinator/ln-modal-coordinator.js +0 -1
  451. package/js/ln-nav/ln-nav.js +0 -1
  452. package/js/ln-number/README.md +0 -149
  453. package/js/ln-number/ln-number.js +0 -1
  454. package/js/ln-number/src/ln-number.js +0 -443
  455. package/js/ln-options/ln-options.js +0 -1
  456. package/js/ln-popover/ln-popover.js +0 -1
  457. package/js/ln-progress/ln-progress.js +0 -1
  458. package/js/ln-progress/src/ln-progress.js +0 -98
  459. package/js/ln-router/ln-router.js +0 -1
  460. package/js/ln-search/README.md +0 -158
  461. package/js/ln-search/ln-search-dev.scss +0 -8
  462. package/js/ln-search/ln-search.js +0 -1
  463. package/js/ln-search/src/ln-search.js +0 -117
  464. package/js/ln-slug/ln-slug.js +0 -1
  465. package/js/ln-sort/ln-sort.js +0 -1
  466. package/js/ln-sort/src/ln-sort.js +0 -178
  467. package/js/ln-sortable/ln-sortable.js +0 -1
  468. package/js/ln-stat/ln-stat.js +0 -1
  469. package/js/ln-table/ln-table.js +0 -1
  470. package/js/ln-table/ln-table.scss +0 -11
  471. package/js/ln-table-coordinator/README.md +0 -73
  472. package/js/ln-table-coordinator/ln-table-coordinator.js +0 -1
  473. package/js/ln-table-coordinator/src/ln-table-coordinator.js +0 -160
  474. package/js/ln-tabs/ln-tabs-dev.scss +0 -18
  475. package/js/ln-tabs/ln-tabs.js +0 -1
  476. package/js/ln-tabs/src/ln-tabs.js +0 -188
  477. package/js/ln-time/ln-time.js +0 -1
  478. package/js/ln-toast/ln-toast.js +0 -1
  479. package/js/ln-toggle/ln-toggle.js +0 -1
  480. package/js/ln-tooltip/ln-tooltip.js +0 -1
  481. package/js/ln-tooltip/ln-tooltip.scss +0 -9
  482. package/js/ln-translations/ln-translations.js +0 -1
  483. package/js/ln-upload/README.md +0 -255
  484. package/js/ln-upload/ln-upload.js +0 -1
  485. package/js/ln-upload/ln-upload.scss +0 -20
  486. package/js/ln-upload/src/ln-upload.js +0 -423
  487. package/js/ln-validate/ln-validate.js +0 -1
  488. package/scss/components/_button.scss +0 -20
  489. package/scss/components/_confirm.scss +0 -5
  490. package/scss/components/_form.scss +0 -107
  491. package/scss/components/_status-badge.scss +0 -4
  492. package/scss/components/_toast.scss +0 -68
  493. package/scss/components/_upload.scss +0 -51
  494. package/scss/config/_theme.scss +0 -216
  495. package/scss/config/mixins/_btn.scss +0 -179
  496. package/scss/config/mixins/_confirm.scss +0 -31
  497. package/scss/config/mixins/_dropdown.scss +0 -141
  498. package/scss/config/mixins/_popover.scss +0 -64
  499. package/scss/ln-ashlar-dev.scss +0 -39
  500. /package/{js → components}/ln-core/positioning.js +0 -0
  501. /package/{js → components}/ln-core/reactive.js +0 -0
  502. /package/{js → components}/ln-filter/ln-filter.scss +0 -0
  503. /package/{js → components}/ln-icon/ln-icon.js +0 -0
  504. /package/{js → components}/ln-icon/src/ln-icon.js +0 -0
  505. /package/{js → components}/ln-search/ln-search.scss +0 -0
  506. /package/{js → components}/ln-toast/template.html +0 -0
  507. /package/{scss → theme}/components/_accordion.scss +0 -0
  508. /package/{scss → theme}/components/_ajax.scss +0 -0
  509. /package/{scss → theme}/components/_alert.scss +0 -0
  510. /package/{scss → theme}/components/_avatar.scss +0 -0
  511. /package/{scss → theme}/components/_breadcrumbs.scss +0 -0
  512. /package/{scss → theme}/components/_card.scss +0 -0
  513. /package/{scss → theme}/components/_chip.scss +0 -0
  514. /package/{scss → theme}/components/_circular-progress.scss +0 -0
  515. /package/{scss → theme}/components/_editor.scss +0 -0
  516. /package/{scss → theme}/components/_empty-state.scss +0 -0
  517. /package/{scss → theme}/components/_filter.scss +0 -0
  518. /package/{scss → theme}/components/_link.scss +0 -0
  519. /package/{scss → theme}/components/_loader.scss +0 -0
  520. /package/{scss → theme}/components/_modal.scss +0 -0
  521. /package/{scss → theme}/components/_nav.scss +0 -0
  522. /package/{scss → theme}/components/_page-header.scss +0 -0
  523. /package/{scss → theme}/components/_popover.scss +0 -0
  524. /package/{scss → theme}/components/_progress.scss +0 -0
  525. /package/{scss → theme}/components/_prose.scss +0 -0
  526. /package/{scss → theme}/components/_scrollbar.scss +0 -0
  527. /package/{scss → theme}/components/_sections.scss +0 -0
  528. /package/{scss → theme}/components/_sidebar.scss +0 -0
  529. /package/{scss → theme}/components/_stat-card.scss +0 -0
  530. /package/{scss → theme}/components/_stepper.scss +0 -0
  531. /package/{scss → theme}/components/_timeline.scss +0 -0
  532. /package/{scss → theme}/components/_tooltip.scss +0 -0
  533. /package/{scss → theme}/components/_translations.scss +0 -0
  534. /package/{scss → theme}/config/_icons.scss +0 -0
  535. /package/{scss → theme}/config/_mixins.scss +0 -0
  536. /package/{scss → theme}/config/mixins/_ajax.scss +0 -0
  537. /package/{scss → theme}/config/mixins/_avatar.scss +0 -0
  538. /package/{scss → theme}/config/mixins/_breadcrumbs.scss +0 -0
  539. /package/{scss → theme}/config/mixins/_breakpoints.scss +0 -0
  540. /package/{scss → theme}/config/mixins/_chip.scss +0 -0
  541. /package/{scss → theme}/config/mixins/_circular-progress.scss +0 -0
  542. /package/{scss → theme}/config/mixins/_display.scss +0 -0
  543. /package/{scss → theme}/config/mixins/_empty-state.scss +0 -0
  544. /package/{scss → theme}/config/mixins/_focus.scss +0 -0
  545. /package/{scss → theme}/config/mixins/_interaction.scss +0 -0
  546. /package/{scss → theme}/config/mixins/_kbd.scss +0 -0
  547. /package/{scss → theme}/config/mixins/_link.scss +0 -0
  548. /package/{scss → theme}/config/mixins/_page-header.scss +0 -0
  549. /package/{scss → theme}/config/mixins/_position.scss +0 -0
  550. /package/{scss → theme}/config/mixins/_progress.scss +0 -0
  551. /package/{scss → theme}/config/mixins/_prose.scss +0 -0
  552. /package/{scss → theme}/config/mixins/_shadows.scss +0 -0
  553. /package/{scss → theme}/config/mixins/_sizing.scss +0 -0
  554. /package/{scss → theme}/config/mixins/_spacing.scss +0 -0
  555. /package/{scss → theme}/config/mixins/_stat-card.scss +0 -0
  556. /package/{scss → theme}/config/mixins/_stepper.scss +0 -0
  557. /package/{scss → theme}/config/mixins/_timeline.scss +0 -0
  558. /package/{scss → theme}/config/mixins/_transitions.scss +0 -0
  559. /package/{scss → theme}/config/mixins/_translations.scss +0 -0
  560. /package/{scss → theme}/tabler-icons.txt +0 -0
@@ -0,0 +1,273 @@
1
+ // ─── Typed Live Attribute Readers ──────────────────────────
2
+ //
3
+ // Scanner constraint: attribute names passed into these readers, and into a
4
+ // `defineAttrs` spec, must always be inline string literals or a `const`
5
+ // bound to a literal — never concatenated or templated.
6
+ // `scripts/sync-ln-schemas.mjs:22-23` is a raw regex over file text; a
7
+ // constructed name is invisible to it and the CI docs gate breaks silently
8
+ // (this already happened once — commit `3495690`).
9
+
10
+ export function attrStr(el, name, fallback) {
11
+ const raw = el.getAttribute(name);
12
+ return raw === null ? fallback : raw;
13
+ }
14
+
15
+ // `0` stays `0` — unlike the `parseInt(...) || 1000` idiom this replaces.
16
+ export function attrInt(el, name, fallback) {
17
+ const parsed = parseInt(el.getAttribute(name), 10);
18
+ return isNaN(parsed) ? fallback : parsed;
19
+ }
20
+
21
+ export function attrBool(el, name, fallback = false) {
22
+ const raw = el.getAttribute(name);
23
+ if (raw === null) return !!fallback;
24
+ const val = raw.trim().toLowerCase();
25
+ if (val === 'false' || val === '0') return false;
26
+ return true;
27
+ }
28
+
29
+ // Allocates a new array per read — do not call inside a per-row loop.
30
+ export function attrList(el, name) {
31
+ return (el.getAttribute(name) || '').split(',').map(s => s.trim()).filter(Boolean);
32
+ }
33
+
34
+ const _enumReaderCache = new Map();
35
+
36
+ /**
37
+ * Cached reader factory for enum attributes.
38
+ * @param {string[]} values - allowed values
39
+ * @param {*} fallback - default value
40
+ * @returns {function(Element, string): *}
41
+ */
42
+ export function attrEnum(values, fallback) {
43
+ const key = (values ? values.join('|') : '') + '::' + fallback;
44
+ if (_enumReaderCache.has(key)) return _enumReaderCache.get(key);
45
+ const valSet = new Set(values || []);
46
+ const reader = function (el, name) {
47
+ const raw = el.getAttribute(name);
48
+ return (raw !== null && valSet.has(raw)) ? raw : fallback;
49
+ };
50
+ _enumReaderCache.set(key, reader);
51
+ return reader;
52
+ }
53
+
54
+ export function attrFloat(el, name, fallback) {
55
+ const parsed = parseFloat(el.getAttribute(name));
56
+ return isNaN(parsed) ? fallback : parsed;
57
+ }
58
+
59
+ export function attrJson(el, name, fallback) {
60
+ const raw = el.getAttribute(name);
61
+ if (!raw) return fallback;
62
+ try {
63
+ return JSON.parse(raw);
64
+ } catch (_) {
65
+ return fallback;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Validates a DOM attribute value against its declared schema entry.
71
+ * Logs a console.warn (with [componentTag] prefix) if the value is invalid.
72
+ *
73
+ * @param {Object} entry - { type, values, min, max, fallback, ... }
74
+ * @param {string|null} value - raw DOM attribute value (null if absent)
75
+ * @param {string} attrName - attribute name (e.g. 'data-ln-modal')
76
+ * @param {string} componentTag - component tag (e.g. 'ln-modal')
77
+ * @param {Element} [el] - optional DOM element carrying the attribute
78
+ * @returns {boolean} true if valid, false if invalid
79
+ */
80
+ export function validateAttrValue(entry, value, attrName, componentTag, el) {
81
+ if (!entry || value === null) return true;
82
+ const tag = componentTag || 'ln-component';
83
+ const type = entry.type;
84
+
85
+ // valueless / unconstrained types
86
+ if (type === 'trigger' || type === 'marker' || type === 'string' || type === 'list' || !type) {
87
+ return true;
88
+ }
89
+
90
+ // Bare attributes (presence-only in HTML) with a declared fallback resolve to fallback in readers
91
+ if (value === '' && entry.fallback !== undefined) {
92
+ return true;
93
+ }
94
+
95
+ const logWarn = (msg) => {
96
+ if (el) console.warn(msg, el);
97
+ else console.warn(msg);
98
+ };
99
+
100
+ if (type === 'boolean') {
101
+ const lower = value.trim().toLowerCase();
102
+ if (lower !== '' && lower !== 'true' && lower !== 'false' && lower !== '1' && lower !== '0') {
103
+ logWarn(`[${tag}] Invalid value "${value}" for boolean attribute "${attrName}". Allowed: "true", "false", or presence-only.`);
104
+ return false;
105
+ }
106
+ return true;
107
+ }
108
+
109
+ if (type === 'enum') {
110
+ const allowed = entry.values || [];
111
+ if (!allowed.includes(value)) {
112
+ logWarn(`[${tag}] Invalid value "${value}" for attribute "${attrName}". Allowed: ${allowed.join(', ')}. Fallback: "${entry.fallback}".`);
113
+ return false;
114
+ }
115
+ return true;
116
+ }
117
+
118
+ if (type === 'integer') {
119
+ if (!/^-?\d+$/.test(value)) {
120
+ logWarn(`[${tag}] Invalid integer "${value}" for attribute "${attrName}". Fallback: ${entry.fallback}.`);
121
+ return false;
122
+ }
123
+ const num = parseInt(value, 10);
124
+ if (entry.min !== undefined && num < entry.min) {
125
+ logWarn(`[${tag}] Value ${num} for attribute "${attrName}" is less than min (${entry.min}).`);
126
+ return false;
127
+ }
128
+ if (entry.max !== undefined && num > entry.max) {
129
+ logWarn(`[${tag}] Value ${num} for attribute "${attrName}" is greater than max (${entry.max}).`);
130
+ return false;
131
+ }
132
+ return true;
133
+ }
134
+
135
+ if (type === 'float') {
136
+ if (isNaN(Number(value))) {
137
+ logWarn(`[${tag}] Invalid float "${value}" for attribute "${attrName}". Fallback: ${entry.fallback}.`);
138
+ return false;
139
+ }
140
+ return true;
141
+ }
142
+
143
+ if (type === 'json') {
144
+ try {
145
+ JSON.parse(value);
146
+ return true;
147
+ } catch (err) {
148
+ logWarn(`[${tag}] Invalid JSON for attribute "${attrName}": ${err.message}. Fallback: ${entry.fallback}.`);
149
+ return false;
150
+ }
151
+ }
152
+
153
+ return true;
154
+ }
155
+
156
+ /**
157
+ * Define live getter-only properties on `instance`, each reading `dom` on
158
+ * every access. Nothing is copied into instance state, so there is no state
159
+ * to invalidate and no sync step.
160
+ *
161
+ * @param {Object} instance
162
+ * @param {Element} dom
163
+ * @param {Object} spec - { propName: [reader, attributeName, fallback] }
164
+ * @returns {Object} instance
165
+ */
166
+ export function defineAttrs(instance, dom, spec) {
167
+ for (const propName in spec) {
168
+ const [reader, attributeName, fallback] = spec[propName];
169
+ Object.defineProperty(instance, propName, {
170
+ // Getter only, no setter — assignment throws in strict mode (ES
171
+ // modules are strict). Deliberate: it forbids a drifting copy.
172
+ get: function () {
173
+ return reader(dom, attributeName, fallback);
174
+ },
175
+ enumerable: true,
176
+ configurable: true
177
+ });
178
+ }
179
+ return instance;
180
+ }
181
+
182
+ /**
183
+ * One table per component is the single source of truth for its HOST
184
+ * attributes. Derivations below read it; nothing else declares an
185
+ * attribute name.
186
+ *
187
+ * Table entry shape:
188
+ * 'data-ln-x': { prop, read, type, values, fallback, min, max, effect, description } — any subset
189
+ *
190
+ * The scanner constraint at the top of this file applies to table KEYS:
191
+ * literal strings only. A computed key is invisible to
192
+ * scripts/sync-ln-schemas.mjs.
193
+ */
194
+ export function attrSpec(table) {
195
+ const spec = {};
196
+ for (const name in table) {
197
+ const entry = table[name];
198
+ if (!entry || !entry.prop) continue;
199
+ let reader = entry.read;
200
+ if (!reader && entry.type) {
201
+ switch (entry.type) {
202
+ case 'enum':
203
+ reader = attrEnum(entry.values, entry.fallback);
204
+ break;
205
+ case 'integer':
206
+ reader = attrInt;
207
+ break;
208
+ case 'float':
209
+ reader = attrFloat;
210
+ break;
211
+ case 'boolean':
212
+ reader = attrBool;
213
+ break;
214
+ case 'list':
215
+ reader = attrList;
216
+ break;
217
+ case 'json':
218
+ reader = attrJson;
219
+ break;
220
+ case 'string':
221
+ default:
222
+ reader = attrStr;
223
+ break;
224
+ }
225
+ }
226
+ if (!reader) reader = attrStr;
227
+ spec[entry.prop] = [reader, name, entry.fallback];
228
+ }
229
+ return spec;
230
+ }
231
+
232
+ export function attrEffects(table) {
233
+ const effects = {};
234
+ for (const name in table) {
235
+ const entry = table[name];
236
+ if (!entry) continue;
237
+ if (entry.effect) effects[name] = entry.effect;
238
+ }
239
+ // null, not {} — `_registerAttrEntry` tests `entry.onAttrChange || entry.effects`,
240
+ // and an empty object is truthy. A table of pure getters would otherwise be
241
+ // pushed into `registry.reactive` and iterated on every data-ln-* mutation
242
+ // on the page while having nothing to run.
243
+ return Object.keys(effects).length ? effects : null;
244
+ }
245
+
246
+ /**
247
+ * The attribute names a registry entry should be indexed under, so the shared
248
+ * observer can reach it by name instead of walking every reactive entry.
249
+ *
250
+ * Note this reads `entry.effects` — the DERIVED table produced by
251
+ * `attrEffects` above — not the raw component table. An entry is indexed
252
+ * under every name it declares, which for a component like `ln-list` means
253
+ * the suffixed names (`data-ln-list-window`) and not only the selector.
254
+ *
255
+ * Internal to ln-core, and deliberately NOT re-exported from index.js: unlike
256
+ * `attrSpec` / `attrEffects`, which take the attribute table a component author
257
+ * writes, this takes a registry entry — a shape no author ever constructs.
258
+ * Publishing it would make the entry shape semver-load-bearing for no caller.
259
+ *
260
+ * @param {Object} entry - a registry entry: { effects, onAttrChange, declared }
261
+ * @returns {Set<string>|null} names to index under, or null for a wildcard —
262
+ * `onAttrChange` without `declared` asks for EVERY data-ln-* mutation and
263
+ * by definition cannot be keyed by name.
264
+ */
265
+ export function reactiveNames(entry) {
266
+ if (entry.onAttrChange && !entry.declared) return null;
267
+
268
+ const names = new Set();
269
+ if (entry.effects) for (const n in entry.effects) names.add(n);
270
+ if (entry.onAttrChange && entry.declared) for (const n of entry.declared) names.add(n);
271
+ return names;
272
+ }
273
+
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Detect the comparison type for a column/field from its current value set.
3
+ * Type is locked ONCE per sort operation (not per pair) — comparing types
4
+ * per-pair breaks comparator transitivity and produces wrong ordering.
5
+ * All non-empty values must be finite numbers for 'number'; otherwise 'string'.
6
+ * @param {Array<unknown>} values
7
+ * @returns {'number' | 'string'}
8
+ */
9
+ export function detectValueType(values) {
10
+ let hasValue = false;
11
+ for (let i = 0; i < values.length; i++) {
12
+ const v = values[i];
13
+ if (v === '' || v == null) continue;
14
+ hasValue = true;
15
+ if (!Number.isFinite(Number(v))) return 'string';
16
+ }
17
+ return hasValue ? 'number' : 'string';
18
+ }
19
+
20
+ /**
21
+ * Compare two raw values given a pre-locked type (see detectValueType).
22
+ * Pass an Intl.Collator instance for locale-aware string comparison —
23
+ * built once by the caller outside the sort loop, never per pair.
24
+ * @param {unknown} a
25
+ * @param {unknown} b
26
+ * @param {'number' | 'string'} type
27
+ * @param {Intl.Collator|null} [collator]
28
+ * @returns {number}
29
+ */
30
+ export function compareValues(a, b, type, collator) {
31
+ if (type === 'number') {
32
+ const na = parseFloat(a);
33
+ const nb = parseFloat(b);
34
+ return (isNaN(na) ? 0 : na) - (isNaN(nb) ? 0 : nb);
35
+ }
36
+ const strA = a != null ? String(a) : '';
37
+ const strB = b != null ? String(b) : '';
38
+ if (collator) return collator.compare(strA, strB);
39
+ return strA < strB ? -1 : strA > strB ? 1 : 0;
40
+ }
@@ -0,0 +1,265 @@
1
+ // Web Crypto API Reusable Cryptographic Helpers
2
+ let _cryptoKey = null;
3
+
4
+ const DEFAULT_SALT = 'ln-ashlar:storage-salt:v1';
5
+ const CHUNK_SIZE = 0x8000; // 32KB chunks for stack-safe Base64 conversion
6
+
7
+ /**
8
+ * Encodes a Uint8Array to a Base64 string in chunks to prevent call-stack overflow on large payloads.
9
+ * @param {Uint8Array} bytes
10
+ * @returns {string}
11
+ */
12
+ export function uint8ToBase64(bytes) {
13
+ let binary = '';
14
+ const len = bytes.byteLength;
15
+ for (let i = 0; i < len; i += CHUNK_SIZE) {
16
+ binary += String.fromCharCode.apply(
17
+ null,
18
+ bytes.subarray(i, Math.min(i + CHUNK_SIZE, len))
19
+ );
20
+ }
21
+ return btoa(binary);
22
+ }
23
+
24
+ /**
25
+ * Decodes a Base64 string to a Uint8Array.
26
+ * @param {string} base64
27
+ * @returns {Uint8Array}
28
+ */
29
+ export function base64ToUint8(base64) {
30
+ const binary = atob(base64);
31
+ const len = binary.length;
32
+ const bytes = new Uint8Array(len);
33
+ for (let i = 0; i < len; i++) {
34
+ bytes[i] = binary.charCodeAt(i);
35
+ }
36
+ return bytes;
37
+ }
38
+
39
+ /**
40
+ * Resolves key and options from overloaded arguments.
41
+ * Ensures an options object like { silent: true } is never passed to WebCrypto as a CryptoKey.
42
+ * @private
43
+ */
44
+ function _resolveKeyAndOptions(keyOrOptions, maybeOptions) {
45
+ let key = _cryptoKey;
46
+ let options = {};
47
+
48
+ if (typeof CryptoKey !== 'undefined' && keyOrOptions instanceof CryptoKey) {
49
+ key = keyOrOptions;
50
+ if (maybeOptions && typeof maybeOptions === 'object') {
51
+ options = maybeOptions;
52
+ }
53
+ } else if (keyOrOptions && typeof keyOrOptions === 'object') {
54
+ options = keyOrOptions;
55
+ if (typeof CryptoKey !== 'undefined' && options.key instanceof CryptoKey) {
56
+ key = options.key;
57
+ }
58
+ }
59
+
60
+ return { key, options };
61
+ }
62
+
63
+ /**
64
+ * Derives a 256-bit AES-GCM CryptoKey using PBKDF2 or SHA-256.
65
+ * @param {string} secretString
66
+ * @param {Object} [options]
67
+ * @param {'pbkdf2'|'sha256'} [options.method='pbkdf2']
68
+ * @param {string|Uint8Array} [options.salt]
69
+ * @param {number} [options.iterations=100000]
70
+ * @returns {Promise<CryptoKey>}
71
+ */
72
+ export async function deriveCryptoKey(secretString, options = {}) {
73
+ if (!secretString) {
74
+ throw new Error('[ln-crypto] Key derivation failed: Secret string is required');
75
+ }
76
+
77
+ const method = options.method || 'pbkdf2';
78
+ const enc = new TextEncoder();
79
+
80
+ if (method === 'sha256') {
81
+ const hash = await crypto.subtle.digest('SHA-256', enc.encode(secretString));
82
+ return crypto.subtle.importKey(
83
+ 'raw',
84
+ hash,
85
+ { name: 'AES-GCM' },
86
+ false,
87
+ ['encrypt', 'decrypt']
88
+ );
89
+ }
90
+
91
+ // PBKDF2 mode
92
+ const saltStr = options.salt || DEFAULT_SALT;
93
+ const salt = typeof saltStr === 'string' ? enc.encode(saltStr) : saltStr;
94
+ const iterations = options.iterations || 100000;
95
+
96
+ const baseKey = await crypto.subtle.importKey(
97
+ 'raw',
98
+ enc.encode(secretString),
99
+ 'PBKDF2',
100
+ false,
101
+ ['deriveKey']
102
+ );
103
+
104
+ return crypto.subtle.deriveKey(
105
+ {
106
+ name: 'PBKDF2',
107
+ salt,
108
+ iterations,
109
+ hash: 'SHA-256'
110
+ },
111
+ baseKey,
112
+ { name: 'AES-GCM', length: 256 },
113
+ false,
114
+ ['encrypt', 'decrypt']
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Sets the active cryptographic key in module memory.
120
+ * Default method is 'sha256' for backward-compatibility with existing at-rest storage caches.
121
+ * Pass { method: 'pbkdf2' } to use PBKDF2.
122
+ * Passing empty/falsy clears the key.
123
+ * @param {string|null} secretString
124
+ * @param {Object} [options]
125
+ * @returns {Promise<void>}
126
+ */
127
+ export async function setCryptoKey(secretString, options = {}) {
128
+ if (!secretString) {
129
+ _cryptoKey = null;
130
+ return;
131
+ }
132
+
133
+ try {
134
+ // Default to sha256 when called as setCryptoKey('secret') for backward compatibility
135
+ const method = options.method || 'sha256';
136
+ _cryptoKey = await deriveCryptoKey(secretString, { ...options, method });
137
+ } catch (err) {
138
+ console.error('[ln-core/crypto] Key derivation failed:', err);
139
+ _cryptoKey = null;
140
+ throw err;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Returns the currently active CryptoKey in module memory.
146
+ * @returns {CryptoKey|null}
147
+ */
148
+ export function getCryptoKey() {
149
+ return _cryptoKey;
150
+ }
151
+
152
+ /**
153
+ * Clears the active cryptographic key in module memory.
154
+ */
155
+ export function clearCryptoKey() {
156
+ _cryptoKey = null;
157
+ }
158
+
159
+ /**
160
+ * Checks if an active cryptographic key is set.
161
+ * @returns {boolean}
162
+ */
163
+ export function hasCryptoKey() {
164
+ return _cryptoKey !== null;
165
+ }
166
+
167
+ /**
168
+ * Encrypts arbitrary data using AES-GCM (256-bit).
169
+ * Fail-closed: Throws an Error if no active key is provided or if encryption fails.
170
+ * @param {any} plainData
171
+ * @param {CryptoKey|Object} [keyOrOptions]
172
+ * @param {Object} [maybeOptions]
173
+ * @returns {Promise<Object>} Version 1 envelope: { v: 1, alg: 'AES-GCM', encrypted: true, iv, data }
174
+ */
175
+ export async function encryptData(plainData, keyOrOptions, maybeOptions) {
176
+ const { key } = _resolveKeyAndOptions(keyOrOptions, maybeOptions);
177
+
178
+ if (plainData === undefined || plainData === null) {
179
+ return plainData;
180
+ }
181
+
182
+ if (!key) {
183
+ throw new Error('[ln-crypto] Encryption failed: No active cryptographic key provided');
184
+ }
185
+
186
+ try {
187
+ const enc = new TextEncoder();
188
+ const iv = crypto.getRandomValues(new Uint8Array(12));
189
+
190
+ const serialized = typeof plainData === 'string' ? plainData : JSON.stringify(plainData);
191
+ const encryptedBuffer = await crypto.subtle.encrypt(
192
+ { name: 'AES-GCM', iv },
193
+ key,
194
+ enc.encode(serialized)
195
+ );
196
+
197
+ return {
198
+ v: 1,
199
+ alg: 'AES-GCM',
200
+ encrypted: true,
201
+ iv: uint8ToBase64(iv),
202
+ data: uint8ToBase64(new Uint8Array(encryptedBuffer))
203
+ };
204
+ } catch (err) {
205
+ console.error('[ln-core/crypto] Encryption failed:', err);
206
+ throw new Error('[ln-crypto] Encryption failed: ' + (err && err.message ? err.message : String(err)));
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Decrypts an encrypted envelope using AES-GCM (256-bit).
212
+ * Fail-closed: Throws an Error if key is missing or decryption fails, unless { silent: true } is passed.
213
+ * Backwards compatible: Decrypts both v1 envelopes and legacy unversioned { encrypted: true, iv, data } payloads.
214
+ * @param {Object} encryptedObject
215
+ * @param {CryptoKey|Object} [keyOrOptions]
216
+ * @param {Object} [maybeOptions]
217
+ * @returns {Promise<any>}
218
+ */
219
+ export async function decryptData(encryptedObject, keyOrOptions, maybeOptions) {
220
+ const { key, options } = _resolveKeyAndOptions(keyOrOptions, maybeOptions);
221
+ const silent = options.silent === true;
222
+
223
+ if (!encryptedObject || !encryptedObject.encrypted) {
224
+ return encryptedObject;
225
+ }
226
+
227
+ if (!key) {
228
+ if (silent) {
229
+ return { ...encryptedObject, decryptionError: true };
230
+ }
231
+ throw new Error('[ln-crypto] Decryption failed: No active cryptographic key provided');
232
+ }
233
+
234
+ if (!encryptedObject.iv || !encryptedObject.data) {
235
+ if (silent) {
236
+ return { ...encryptedObject, decryptionError: true };
237
+ }
238
+ throw new Error('[ln-crypto] Decryption failed: Malformed envelope (missing iv or data)');
239
+ }
240
+
241
+ try {
242
+ const dec = new TextDecoder();
243
+ const iv = base64ToUint8(encryptedObject.iv);
244
+ const encryptedBuffer = base64ToUint8(encryptedObject.data);
245
+
246
+ const decryptedBuffer = await crypto.subtle.decrypt(
247
+ { name: 'AES-GCM', iv },
248
+ key,
249
+ encryptedBuffer
250
+ );
251
+
252
+ const decoded = dec.decode(decryptedBuffer);
253
+ try {
254
+ return JSON.parse(decoded);
255
+ } catch (_) {
256
+ return decoded;
257
+ }
258
+ } catch (err) {
259
+ if (silent) {
260
+ return { ...encryptedObject, decryptionError: true };
261
+ }
262
+ console.error('[ln-core/crypto] Decryption failed. Key may be incorrect or payload tampered:', err);
263
+ throw new Error('[ln-crypto] Decryption failed. Key may be incorrect or payload tampered: ' + (err && err.message ? err.message : String(err)));
264
+ }
265
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Parses raw input (Unix seconds, milliseconds, or ISO string) into a Date object.
3
+ * @param {unknown} raw
4
+ * @returns {Date|null}
5
+ */
6
+ export function parseDateInput(raw) {
7
+ if (raw === null || raw === undefined || raw === '') return null;
8
+
9
+ if (raw instanceof Date) {
10
+ return isNaN(raw.getTime()) ? null : raw;
11
+ }
12
+
13
+ const num = Number(raw);
14
+ if (!isNaN(num) && num > 0) {
15
+ // If timestamp is in seconds (< 10^11), convert to ms
16
+ const ms = num < 1e11 ? num * 1000 : num;
17
+ const d = new Date(ms);
18
+ return isNaN(d.getTime()) ? null : d;
19
+ }
20
+
21
+ if (typeof raw === 'string') {
22
+ const str = raw.trim();
23
+ if (!str) return null;
24
+ // Date-only ISO parses as UTC midnight, which reads back as the previous day west of UTC.
25
+ const ymd = /^(\d{4})-(\d{2})-(\d{2})$/.exec(str);
26
+ if (ymd) {
27
+ const year = +ymd[1], month = +ymd[2], day = +ymd[3];
28
+ const local = new Date(year, month - 1, day);
29
+ if (local.getFullYear() !== year || local.getMonth() !== month - 1 || local.getDate() !== day) return null;
30
+ return local;
31
+ }
32
+ const d = new Date(str);
33
+ return isNaN(d.getTime()) ? null : d;
34
+ }
35
+
36
+ return null;
37
+ }
38
+
39
+ /**
40
+ * Formats a Date object to an ISO date string (YYYY-MM-DD).
41
+ * @param {Date} date
42
+ * @returns {string}
43
+ */
44
+ export function formatDateToISO(date) {
45
+ if (!date || !(date instanceof Date) || isNaN(date.getTime())) return '';
46
+ const y = date.getFullYear();
47
+ const m = String(date.getMonth() + 1).padStart(2, '0');
48
+ const d = String(date.getDate()).padStart(2, '0');
49
+ return y + '-' + m + '-' + d;
50
+ }