@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
@@ -7,9 +7,20 @@ import { QueueStorage } from './queue-storage';
7
7
  const BACKOFF_LADDER = [2000, 5000, 15000, 60000, 300000];
8
8
  const MAX_ATTEMPTS = 8;
9
9
  const LEASE_MS = 60000;
10
-
11
10
  if (window[DOM_ATTRIBUTE] !== undefined) return;
12
11
 
12
+ // ─── Attribute Contract (SSOT) ──────────────────────────
13
+ function _syncOnline(el) {
14
+ const instance = el[DOM_ATTRIBUTE];
15
+ if (!instance) return;
16
+ instance._drain();
17
+ }
18
+
19
+ const ATTRIBUTES = {
20
+ 'data-ln-api-queue': { type: 'marker', description: 'Mounts offline API synchronization queue backed by IndexedDB' },
21
+ 'data-ln-api-queue-online': { effect: _syncOnline, type: 'enum', values: ['true', 'false'], fallback: 'auto', description: 'Network connectivity override (true/false, or auto-detect from navigator.onLine)' }
22
+ };
23
+
13
24
  function _uuid() {
14
25
  try { return crypto.randomUUID(); }
15
26
  catch (_) {
@@ -31,7 +42,7 @@ import { QueueStorage } from './queue-storage';
31
42
  dom[DOM_ATTRIBUTE] = this;
32
43
 
33
44
  const coordinatorEl = dom.closest('[data-ln-data-coordinator]');
34
- this.scope = dom.getAttribute(DOM_SELECTOR) || (coordinatorEl ? coordinatorEl.getAttribute('data-ln-data-coordinator') : null) || 'default';
45
+ this.scope = dom.id || (coordinatorEl ? coordinatorEl.id : null) || 'default';
35
46
 
36
47
  this._paused = false;
37
48
  this._timers = new Map();
@@ -51,9 +62,12 @@ import { QueueStorage } from './queue-storage';
51
62
  }
52
63
  return _storage.getPaused(self.scope);
53
64
  })
54
- .then(paused => {
55
- self._paused = !!paused;
56
- if (self._paused) dispatch(self.dom, 'ln-api-queue:paused', { reason: 'auth', restored: true });
65
+ .then(pausedReason => {
66
+ self._paused = !!pausedReason;
67
+ if (self._paused) {
68
+ const reason = typeof pausedReason === 'string' ? pausedReason : 'auth';
69
+ dispatch(self.dom, 'ln-api-queue:paused', { reason: reason, restored: true });
70
+ }
57
71
  return self._emitPendingCount();
58
72
  })
59
73
  .then(() => self._drain())
@@ -240,6 +254,16 @@ import { QueueStorage } from './queue-storage';
240
254
  });
241
255
  };
242
256
 
257
+ _component.prototype._onPause = function () {
258
+ const self = this;
259
+ return _storage.setPaused(self.scope, 'manual').then(() => {
260
+ self._paused = true;
261
+ dispatch(self.dom, 'ln-api-queue:paused', { reason: 'manual' });
262
+ }).catch(error => {
263
+ dispatch(self.dom, 'ln-api-queue:error', { operation: 'pause', error });
264
+ });
265
+ };
266
+
243
267
  _component.prototype._onDrain = function () {
244
268
  const self = this;
245
269
  return _storage.resetFailed(self.scope).then(() => {
@@ -272,6 +296,7 @@ import { QueueStorage } from './queue-storage';
272
296
  remap: e => self._onRemap(e),
273
297
  resolveCreate: e => self._onResolveCreate(e),
274
298
  resume: () => self._onResume(),
299
+ pause: () => self._onPause(),
275
300
  drain: () => self._onDrain(),
276
301
  clear: () => self._onClear()
277
302
  };
@@ -282,6 +307,7 @@ import { QueueStorage } from './queue-storage';
282
307
  self.dom.addEventListener('ln-api-queue:request-remap', self._handlers.remap);
283
308
  self.dom.addEventListener('ln-api-queue:resolve-create', self._handlers.resolveCreate);
284
309
  self.dom.addEventListener('ln-api-queue:request-resume', self._handlers.resume);
310
+ self.dom.addEventListener('ln-api-queue:request-pause', self._handlers.pause);
285
311
  self.dom.addEventListener('ln-api-queue:request-drain', self._handlers.drain);
286
312
  self.dom.addEventListener('ln-api-queue:request-clear', self._handlers.clear);
287
313
  };
@@ -296,6 +322,7 @@ import { QueueStorage } from './queue-storage';
296
322
  self.dom.removeEventListener('ln-api-queue:request-remap', self._handlers.remap);
297
323
  self.dom.removeEventListener('ln-api-queue:resolve-create', self._handlers.resolveCreate);
298
324
  self.dom.removeEventListener('ln-api-queue:request-resume', self._handlers.resume);
325
+ self.dom.removeEventListener('ln-api-queue:request-pause', self._handlers.pause);
299
326
  self.dom.removeEventListener('ln-api-queue:request-drain', self._handlers.drain);
300
327
  self.dom.removeEventListener('ln-api-queue:request-clear', self._handlers.clear);
301
328
  window.removeEventListener('online', self._onlineHandler);
@@ -303,18 +330,10 @@ import { QueueStorage } from './queue-storage';
303
330
  self._timers.forEach(timer => clearTimeout(timer));
304
331
  self._timers.clear();
305
332
 
306
- dispatch(self.dom, 'ln-api-queue:destroyed', { scope: self.scope });
307
333
  delete self.dom[DOM_ATTRIBUTE];
308
334
  };
309
335
 
310
- function _syncAttr(el) {
311
- const instance = el[DOM_ATTRIBUTE];
312
- if (!instance) return;
313
- instance._drain();
314
- }
315
-
316
336
  registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-api-queue', {
317
- extraAttributes: ['data-ln-api-queue-online'],
318
- onAttributeChange: _syncAttr
337
+ attributes: ATTRIBUTES
319
338
  });
320
339
  })();
@@ -289,7 +289,7 @@ export class QueueStorage {
289
289
  if (reason === 'auth') {
290
290
  entry.status = 'pending';
291
291
  outbox.put(entry);
292
- meta.put({ key: pauseKey(scope), value: true });
292
+ meta.put({ key: pauseKey(scope), value: 'auth' });
293
293
  result = { status: 'auth', entry };
294
294
  return;
295
295
  }
@@ -386,7 +386,10 @@ export class QueueStorage {
386
386
  return new Promise((resolve, reject) => {
387
387
  const tx = db.transaction(META, 'readonly');
388
388
  const request = tx.objectStore(META).get(pauseKey(scope));
389
- request.onsuccess = () => resolve(!!(request.result && request.result.value));
389
+ request.onsuccess = () => {
390
+ const val = request.result ? request.result.value : false;
391
+ resolve(val || false);
392
+ };
390
393
  request.onerror = () => reject(requestError(request, 'Queue pause-state read failed'));
391
394
  });
392
395
  });
@@ -397,7 +400,8 @@ export class QueueStorage {
397
400
  if (!db) return;
398
401
  return new Promise((resolve, reject) => {
399
402
  const tx = db.transaction(META, 'readwrite');
400
- tx.objectStore(META).put({ key: pauseKey(scope), value: !!paused });
403
+ const value = typeof paused === 'string' ? paused : (paused ? 'manual' : false);
404
+ tx.objectStore(META).put({ key: pauseKey(scope), value: value });
401
405
  tx.oncomplete = () => resolve();
402
406
  tx.onerror = () => reject(tx.error || new Error('Queue pause-state write failed'));
403
407
  tx.onabort = () => reject(tx.error || new Error('Queue pause-state write aborted'));
@@ -1,127 +1,129 @@
1
- # ln-autoresize
2
-
3
- A zero-dependency, high-performance **UX Helper Primitive** (~47 lines of JavaScript) that dynamically resizes a `<textarea>` to track its content. It grows as the user types and collapses instantly as text is deleted.
4
-
5
- ---
6
-
7
- ## 🧭 Philosophy & Architecture
8
-
9
- 1. **Platform-First Execution:** Instead of introducing heavy observers or layouts, `ln-autoresize` hooks directly into the browser's native layout engine. By resetting height to `auto` before reading `scrollHeight` inside the event loop, it forces a synchronous, flicker-free layout calculation.
10
- 2. **Strict Concern Scope:** The primitive is stateless. Ceiling limits, minimum bounds, and manual resize handles are defined exclusively via standard CSS classes. The script only handles active observation.
11
- 3. **Reactive Synchronization:** Data flows strictly through DOM events. Programmatic changes must trigger standard events (`input` / `change`) so that dependent primitives can adapt in synchrony.
12
-
13
- ---
14
-
15
- ## 📦 Minimal Blueprint
16
-
17
- ```html
18
- <textarea data-ln-autoresize rows="1" placeholder="Type here..."></textarea>
19
- ```
20
-
21
- To cap growth at a maximum height and enable scroll past it, pair the attribute with pure CSS:
22
-
23
- ```scss
24
- textarea[data-ln-autoresize] {
25
- resize: none; // Removes conflicting manual drag handle
26
- max-height: 6rem; // Defines height ceiling
27
- overflow-y: auto; // Reveals scrollbar at ceiling
28
- }
29
- ```
30
-
31
- > [!TIP]
32
- > Always set `rows="1"` on the HTML element. This ensures the initial empty height matches the post-initialization state and prevents visual snap-shut on first paint.
33
-
34
- ---
35
-
36
- ## 🛠️ Declarative API Contract
37
-
38
- ### HTML Attributes
39
-
40
- | Attribute | Elements | Description |
41
- | :--- | :--- | :--- |
42
- | `data-ln-autoresize` | `<textarea>` | Observation marker. Presence creates the instance and runs initial measurement. |
43
-
44
- ### JS API
45
-
46
- Access the utility instance directly via the `lnAutoresize` property on the textarea element:
47
-
48
- ```javascript
49
- const textarea = document.getElementById('my-textarea');
50
-
51
- // 1. Force a manual re-measure (essential after parent reveals, font loads, etc.)
52
- textarea.lnAutoresize._resize();
53
-
54
- // 2. Tear down event listeners and clear inline styles
55
- textarea.lnAutoresize.destroy();
56
- ```
57
-
58
- ---
59
-
60
- ## ⚡ DOM Events
61
-
62
- `ln-autoresize` does not emit custom events. It relies entirely on standard browser interactions:
63
-
64
- - **Listens to `input`:** Triggers `_resize()` on keystrokes, pastes, and deletes.
65
- - **Listens to `change`:** Triggers `_resize()` on value commits.
66
-
67
- ---
68
-
69
- ## ⚠️ Common Pitfalls
70
-
71
- - **Setting `textarea.value` directly:** Programmatic writes are silent in the DOM. The component will not detect value updates unless you dispatch a synthetic event:
72
- ```javascript
73
- textarea.value = 'New text content';
74
- textarea.dispatchEvent(new Event('input', { bubbles: true }));
75
- ```
76
- - **Mounting in hidden parents:** A textarea inside a `display: none` container measures `scrollHeight` as `0`. When revealed later, it will appear collapsed. Force a re-measure manually after reveal:
77
- ```javascript
78
- textarea.lnAutoresize._resize();
79
- ```
80
- - **Conflicting manual drag handles:** By default, textareas may have `resize: vertical` applied. This lets users manual resize the input, which is instantly overridden by the script on the next keystroke. Set `resize: none` to clean up the interface.
81
-
82
- ---
83
-
84
- ## 🔧 Internals
85
-
86
- Source: `js/ln-autoresize/ln-autoresize.js`. A pure presentation utility — owns no data, emits no custom events, cooperates with no other component outside the `input` platform event.
87
-
88
- ### Instance state
89
-
90
- | Property | Type | Description |
91
- |----------|------|-------------|
92
- | `dom` | `HTMLTextAreaElement` | The textarea, constructor argument |
93
- | `_onInput` | `Function` | Bound `input` handler, kept for `destroy()` unbind |
94
-
95
- No cached "current height" — `_resize` always reads `scrollHeight` fresh, so external CSS changes (`max-height`, font-size, padding) are picked up on the next keystroke.
96
-
97
- ### Resize mechanism
98
-
99
- ```
100
- _resize():
101
- 1. style.height = 'auto'
102
- 2. read scrollHeight
103
- 3. style.height = scrollHeight + 'px'
104
- ```
105
-
106
- Step 1 is what makes it shrink, not just grow: `scrollHeight` reports the explicit `height` when content fits inside it, so without the reset every measurement would ratchet upward only. The reset + re-read happen synchronously in one tick, so the browser never paints the intermediate `auto` state — no flicker.
107
-
108
- The constructor also calls `_resize()` once before returning, to size server-rendered pre-filled values and late-attached fields (`setAttribute` after the fact) on first paint rather than first keystroke. If the textarea is hidden at construction (`display: none` ancestor), `scrollHeight` reads `0` and there's no `ResizeObserver`/`IntersectionObserver` to catch a later reveal — call `_resize()` manually after showing it.
109
-
110
- ### Tag validation
111
-
112
- The constructor checks `dom.tagName !== 'TEXTAREA'` and, if true, warns and returns `this` early with no `dom`/listener. The element is still marked initialized, so re-attaching the attribute after swapping in a real `<textarea>` needs `destroy()` first.
113
-
114
- ### MutationObserver via `registerComponent`
115
-
116
- Standard shared observer on `document.body`: `childList/subtree` catches new `[data-ln-autoresize]` textareas anywhere; `attributes` (filtered to the one attribute) catches late `setAttribute` addition. Only attribute *presence* matters — no `onAttributeChange` callback, so value changes and attribute removal are no-ops.
117
-
118
- ### Destroy
119
-
120
- Idempotent (bails if already torn down). Unbinds `_onInput`, clears `style.height` (reverting to the CSS-driven `rows`-based height), deletes the instance property. Does not remove the `data-ln-autoresize` attribute — the caller owns it, so a later rescan can re-create the instance.
121
-
122
- ### Cross-component coordination
123
-
124
- No ln-prefixed import/listen/dispatch — only the platform `input` event. Two paths feed it synthetic `input` events:
125
-
126
- - **`ln-form:fill`** — `ln-form`'s `fill()` writes `.value` then dispatches `input` on each populated field; autoresize catches it and re-measures. Direct `.value =` writes from project code skip this and will not resize.
127
- - **`lnForm.reset()`** — walks fields dispatching synthetic `input`/`change` after `dom.reset()`, so cleared textareas shrink back. The bare native `<button type="reset">` path does NOT dispatch synthetic `input` (intentionally minimal); wire it manually or use the `lnForm.reset()` API if auto-shrink is needed there.
1
+ # ln-autoresize
2
+
3
+ > Applied directly to a `<textarea data-ln-autoresize rows="1">`. It listens for native `input` events:
4
+ > in the handler, it resets `textarea.style.height = 'auto'`, reads `textarea.scrollHeight`, and sets
5
+ > `textarea.style.height = textarea.scrollHeight + 'px'`. It carries zero state, executing a synchronous layout calculation to expand and collapse the box dynamically.
6
+
7
+ ---
8
+
9
+ ## 🧭 Philosophy & Architecture
10
+
11
+ 1. **Platform-First Execution:** Instead of introducing heavy observers or layouts, `ln-autoresize` hooks directly into the browser's native layout engine. By resetting height to `auto` before reading `scrollHeight` inside the event loop, it forces a synchronous, flicker-free layout calculation.
12
+ 2. **Strict Concern Scope:** The primitive is stateless. Ceiling limits, minimum bounds, and manual resize handles are defined exclusively via standard CSS classes. The script only handles active observation.
13
+ 3. **Reactive Synchronization:** Data flows strictly through DOM events. Programmatic changes must trigger standard events (`input` / `change`) so that dependent primitives can adapt in synchrony.
14
+
15
+ ---
16
+
17
+ ## 📦 Minimal Blueprint
18
+
19
+ ```html
20
+ <textarea data-ln-autoresize rows="1" placeholder="Type here..."></textarea>
21
+ ```
22
+
23
+ To cap growth at a maximum height and enable scroll past it, pair the attribute with pure CSS:
24
+
25
+ ```scss
26
+ textarea[data-ln-autoresize] {
27
+ resize: none; // Removes conflicting manual drag handle
28
+ max-height: 6rem; // Defines height ceiling
29
+ overflow-y: auto; // Reveals scrollbar at ceiling
30
+ }
31
+ ```
32
+
33
+ > [!TIP]
34
+ > Always set `rows="1"` on the HTML element. This ensures the initial empty height matches the post-initialization state and prevents visual snap-shut on first paint.
35
+
36
+ ---
37
+
38
+ ## 🛠️ Declarative API Contract
39
+
40
+ ### HTML Attributes
41
+
42
+ | Attribute | Elements | Description |
43
+ | :--- | :--- | :--- |
44
+ | `data-ln-autoresize` | `<textarea>` | Observation marker. Presence creates the instance and runs initial measurement. |
45
+
46
+ ### JS API
47
+
48
+ Access the utility instance directly via the `lnAutoresize` property on the textarea element:
49
+
50
+ ```javascript
51
+ const textarea = document.getElementById('my-textarea');
52
+
53
+ // 1. Force a manual re-measure (essential after parent reveals, font loads, etc.)
54
+ textarea.lnAutoresize._resize();
55
+
56
+ // 2. Tear down event listeners and clear inline styles
57
+ textarea.lnAutoresize.destroy();
58
+ ```
59
+
60
+ ---
61
+
62
+ ## ⚡ DOM Events
63
+
64
+ `ln-autoresize` does not emit custom events. It relies entirely on standard browser interactions:
65
+
66
+ - **Listens to `input`:** Triggers `_resize()` on keystrokes, pastes, and deletes.
67
+ - **Listens to `change`:** Triggers `_resize()` on value commits.
68
+
69
+ ---
70
+
71
+ ## ⚠️ Common Pitfalls
72
+
73
+ - **Setting `textarea.value` directly:** Programmatic writes are silent in the DOM. The component will not detect value updates unless you dispatch a synthetic event:
74
+ ```javascript
75
+ textarea.value = 'New text content';
76
+ textarea.dispatchEvent(new Event('input', { bubbles: true }));
77
+ ```
78
+ - **Mounting in hidden parents:** A textarea inside a `display: none` container measures `scrollHeight` as `0`. When revealed later, it will appear collapsed. Force a re-measure manually after reveal:
79
+ ```javascript
80
+ textarea.lnAutoresize._resize();
81
+ ```
82
+ - **Conflicting manual drag handles:** By default, textareas may have `resize: vertical` applied. This lets users manual resize the input, which is instantly overridden by the script on the next keystroke. Set `resize: none` to clean up the interface.
83
+
84
+ ---
85
+
86
+ ## 🔧 Internals
87
+
88
+ Source: `components/ln-autoresize/ln-autoresize.js`. A pure presentation utility — owns no data, emits no custom events, cooperates with no other component outside the `input` platform event.
89
+
90
+ ### Instance state
91
+
92
+ | Property | Type | Description |
93
+ |----------|------|-------------|
94
+ | `dom` | `HTMLTextAreaElement` | The textarea, constructor argument |
95
+ | `_onInput` | `Function` | Bound `input` handler, kept for `destroy()` unbind |
96
+
97
+ No cached "current height" — `_resize` always reads `scrollHeight` fresh, so external CSS changes (`max-height`, font-size, padding) are picked up on the next keystroke.
98
+
99
+ ### Resize mechanism
100
+
101
+ ```
102
+ _resize():
103
+ 1. style.height = 'auto'
104
+ 2. read scrollHeight
105
+ 3. style.height = scrollHeight + 'px'
106
+ ```
107
+
108
+ Step 1 is what makes it shrink, not just grow: `scrollHeight` reports the explicit `height` when content fits inside it, so without the reset every measurement would ratchet upward only. The reset + re-read happen synchronously in one tick, so the browser never paints the intermediate `auto` state — no flicker.
109
+
110
+ The constructor also calls `_resize()` once before returning, to size server-rendered pre-filled values and late-attached fields (`setAttribute` after the fact) on first paint rather than first keystroke. If the textarea is hidden at construction (`display: none` ancestor), `scrollHeight` reads `0` and there's no `ResizeObserver`/`IntersectionObserver` to catch a later reveal — call `_resize()` manually after showing it.
111
+
112
+ ### Tag validation
113
+
114
+ The constructor checks `dom.tagName !== 'TEXTAREA'` and, if true, warns and returns `this` early with no `dom`/listener. The element is still marked initialized, so re-attaching the attribute after swapping in a real `<textarea>` needs `destroy()` first.
115
+
116
+ ### MutationObserver via `registerComponent`
117
+
118
+ Standard shared observer on `document.body`: `childList/subtree` catches new `[data-ln-autoresize]` textareas anywhere; `attributes` (filtered to the one attribute) catches late `setAttribute` addition. Only attribute *presence* matters — no `onAttributeChange` callback, so value changes and attribute removal are no-ops.
119
+
120
+ ### Destroy
121
+
122
+ Idempotent (bails if already torn down). Unbinds `_onInput`, clears `style.height` (reverting to the CSS-driven `rows`-based height), deletes the instance property. Does not remove the `data-ln-autoresize` attribute — the caller owns it, so a later rescan can re-create the instance.
123
+
124
+ ### Cross-component coordination
125
+
126
+ No ln-prefixed import/listen/dispatch — only the platform `input` event. Two paths feed it synthetic `input` events:
127
+
128
+ - **`ln-form:fill`** — `ln-form`'s `fill()` writes `.value` then dispatches `input` on each populated field; autoresize catches it and re-measures. Direct `.value =` writes from project code skip this and will not resize.
129
+ - **`lnForm.reset()`** — walks fields dispatching synthetic `input`/`change` after `dom.reset()`, so cleared textareas shrink back. The bare native `<button type="reset">` path does NOT dispatch synthetic `input` (intentionally minimal); wire it manually or use the `lnForm.reset()` API if auto-shrink is needed there.
@@ -0,0 +1,8 @@
1
+ @use '../../theme/config/mixins' as *;
2
+
3
+ [data-ln-debug] {
4
+ // 1. Host Element Check: data-ln-autoresize belongs only on <textarea>
5
+ [data-ln-autoresize]:not(textarea) {
6
+ @include dev-inline-error("data-ln-autoresize belongs only on <textarea> elements");
7
+ }
8
+ }
@@ -0,0 +1 @@
1
+ (function(){"use strict";function O(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function p(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let r=1;r<t.length;r++)if(t[r]&&t[r].nodeType===1){o=t[r];break}if(!p(o))return}e.apply(console,t)}}function M(e,t,n){const o=n||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function b(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){b(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const x={};function B(e,t){x[e]=t}function N(e){return x[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=B,window.lnCore.getDataMapper=N);function W(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,b(function(){new MutationObserver(function(){M(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const E={};function j(e,t){if(!e||typeof t!="object")return;const n=e.toLowerCase().split("-")[0];E[n]=t}function V(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return E[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=j,window.lnCore.getLocaleFallback=V,window.lnCore.ensureLocaleObserver=W);const C={};function H(e,t){C[e]||(C[e]=document.querySelector('[data-ln-template="'+e+'"]'));const n=C[e];return n?n.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function L(e,t){if(!e||!t)return e;const n=e.querySelectorAll("[data-ln-field]");for(let l=0;l<n.length;l++){const c=n[l],s=c.getAttribute("data-ln-field");t[s]!=null&&(c.textContent=t[s])}const o=e.querySelectorAll("[data-ln-attr]");for(let l=0;l<o.length;l++){const c=o[l],s=c.getAttribute("data-ln-attr").split(",");for(let u=0;u<s.length;u++){const a=s[u].trim().split(":");if(a.length!==2)continue;const d=a[0].trim(),f=a[1].trim();t[f]!=null&&c.setAttribute(d,t[f])}}const r=e.querySelectorAll("[data-ln-show]");for(let l=0;l<r.length;l++){const c=r[l],s=c.getAttribute("data-ln-show");s in t&&c.classList.toggle("hidden",!t[s])}const i=e.querySelectorAll("[data-ln-class]");for(let l=0;l<i.length;l++){const c=i[l],s=c.getAttribute("data-ln-class").split(",");for(let u=0;u<s.length;u++){const a=s[u].trim().split(":");if(a.length!==2)continue;const d=a[0].trim(),f=a[1].trim();f in t&&c.classList.toggle(d,!!t[f])}}return e}function z(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const n=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<n.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",n[o],t??null),n[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)L(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let n=0;n<t.length;n++)t[n].textContent=""}})));function $(e,t){if(!e||!t)return e;const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;n.nextNode();){const i=n.currentNode;i.textContent.indexOf("{{")!==-1&&(i.textContent=i.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(l,c){return t[c]!==void 0?t[c]:""}))}const o=function(i,l){return t[l]!==void 0?t[l]:""},r=Array.from(e.querySelectorAll("*"));e.nodeType===1&&r.push(e);for(let i=0;i<r.length;i++){const l=r[i],c=l.attributes;for(let s=0;s<c.length;s++){const u=c[s];u.value.indexOf("{{")!==-1&&l.setAttribute(u.name,u.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function U(e,t,n,o,r,i){const l={};for(let s=0;s<e.children.length;s++){const u=e.children[s],a=u.getAttribute("data-ln-render-key");a&&(l[a]=u)}const c=document.createDocumentFragment();for(let s=0;s<t.length;s++){const u=t[s],a=String(o(u));let d=l[a];if(d)r(d,u,s);else{const f=H(n,i);if(!f||($(f,u),d=f.firstElementChild,!d))continue;d.setAttribute("data-ln-render-key",a),r(d,u,s)}c.appendChild(d)}e.textContent="",e.appendChild(c)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=$,window.lnCore.fill=L,window.lnCore.lnFill=z,window.lnCore.renderList=U);function T(e,t,n,o,r){if(!e||t===null)return!0;const i=o||"ln-component",l=e.type;if(l==="trigger"||l==="marker"||l==="string"||l==="list"||!l||t===""&&e.fallback!==void 0)return!0;const c=s=>{r?console.warn(s,r):console.warn(s)};if(l==="boolean"){const s=t.trim().toLowerCase();return s!==""&&s!=="true"&&s!=="false"&&s!=="1"&&s!=="0"?(c(`[${i}] Invalid value "${t}" for boolean attribute "${n}". Allowed: "true", "false", or presence-only.`),!1):!0}if(l==="enum"){const s=e.values||[];return s.includes(t)?!0:(c(`[${i}] Invalid value "${t}" for attribute "${n}". Allowed: ${s.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(l==="integer"){if(!/^-?\d+$/.test(t))return c(`[${i}] Invalid integer "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1;const s=parseInt(t,10);return e.min!==void 0&&s<e.min?(c(`[${i}] Value ${s} for attribute "${n}" is less than min (${e.min}).`),!1):e.max!==void 0&&s>e.max?(c(`[${i}] Value ${s} for attribute "${n}" is greater than max (${e.max}).`),!1):!0}if(l==="float")return isNaN(Number(t))?(c(`[${i}] Invalid float "${t}" for attribute "${n}". Fallback: ${e.fallback}.`),!1):!0;if(l==="json")try{return JSON.parse(t),!0}catch(s){return c(`[${i}] Invalid JSON for attribute "${n}": ${s.message}. Fallback: ${e.fallback}.`),!1}return!0}function Q(e){const t={};for(const n in e){const o=e[n];o&&o.effect&&(t[n]=o.effect)}return Object.keys(t).length?t:null}function K(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const n in e.effects)t.add(n);if(e.onAttrChange&&e.declared)for(const n of e.declared)t.add(n);return t}function y(e,t,n,o){if(e.nodeType!==1)return;const i=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",l=Array.from(e.querySelectorAll(i));e.matches&&e.matches(i)&&l.push(e);for(const c of l)if(!c[n]){window.lnCore._persistSink&&c.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(c,t);try{c[n]=new o(c)}catch(s){console.error("["+n+"] init failed",c,s)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function G(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function J(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function D(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function X(e){const t=D(),n=e.observed||[];for(let o=0;o<n.length;o++){const r=n[o];t.byAttr.has(r)||t.byAttr.set(r,[]),t.byAttr.get(r).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const r=t.byDeclaredAttr.get(o);r.some(i=>i.componentTag===e.componentTag)||r.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=K(e);if(o===null)t.reactiveWildcard.push(e);else for(const r of o)t.byReactive.has(r)||t.byReactive.set(r,[]),t.byReactive.get(r).push(e)}e.persist&&t.persist.push(e)}function I(e,t,n,o){for(let r=0;r<e.length;r++){const i=e[r];if(!t[i.attribute])continue;const l=i.effects&&i.effects[n];l?l(t,n,o):i.onAttrChange&&(!i.declared||i.declared.has(n))&&i.onAttrChange(t,n,o)}}function P(e){const t=e.target,n=e.attributeName;if(e.oldValue===t.getAttribute(n))return;const o=D(),r=o.byAttr.get(n);if(O()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(n)&&p(t)){const i=o.byDeclaredAttr.get(n),l=t.getAttribute(n);for(let c=0;c<i.length;c++)T(i[c].spec,l,n,i[c].componentTag,t)}if(window.lnCore._debugSink&&(n.indexOf("data-ln-")===0||r)&&window.lnCore._debugSink("attr",n,t,{oldValue:e.oldValue,newValue:t.getAttribute(n)}),n.indexOf("data-ln-")===0){const i=o.byReactive.get(n);i&&I(i,t,n,e.oldValue),o.reactiveWildcard.length&&I(o.reactiveWildcard,t,n,e.oldValue)}if(r)for(let i=0;i<r.length;i++){const l=r[i];if(l.handler){l.handler(t,n,e.oldValue);continue}l.onAttributeChange&&t[l.attribute]?l.onAttributeChange(t,n):(y(t,l.selector,l.attribute,l.ComponentFn),l.onInit&&l.onInit(t))}}function Y(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,b(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++)try{P(t[n])}catch(o){console.error("[ln-core] mutation handler failed",t[n].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function R(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function Z(e){const t=R();if(t.length){if(e.target)for(let n=0;n<t.length;n++){const o=t[n];if(o.onSubtreeChange){const r=o.query,i=e.target.nodeType===1?e.target.matches(r)?e.target:e.target.closest(r):e.target.parentElement?e.target.parentElement.closest(r):null;i&&o.onSubtreeChange(i,e)}}for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r];y(o,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(o)}}for(let n=0;n<e.removedNodes.length;n++){const o=e.removedNodes[n];if(o.nodeType===1)for(let r=0;r<t.length;r++){const i=t[r],l=i.query,c=Array.from(o.querySelectorAll(l));o.matches&&o.matches(l)&&c.push(o);for(let s=0;s<c.length;s++){const u=c[s];if(!document.contains(u)){const a=u[i.attribute];if(a&&typeof a.destroy=="function")try{a.destroy()}catch(d){console.error("["+i.attribute+"] destroy failed",u,d)}delete u[i.attribute]}}}}}}function ee(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,b(function(){new MutationObserver(function(t){for(let n=0;n<t.length;n++){const o=t[n];if(o.type==="childList")try{Z(o)}catch(r){console.error("[ln-core] lifecycle handler failed",o.target,r)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function te(e,t,n,o,r={}){const i=r.extraAttributes||[],l=r.onAttributeChange||null,c=r.onSubtreeChange||null,s=r.onInit||null,u=r.onAttrChange||null,a=r.effects||null,d=r.attributes||null,f=d?Q(d):a,de=d?new Set(Object.keys(d)):null,ae=r.persist||null;function g(_){const w=_||document.body;if(y(w,e,t,n),d&&O())for(const h in d){const we=d[h],v=Array.from(w.querySelectorAll("["+h+"]"));w.matches&&w.matches("["+h+"]")&&v.push(w);for(let S=0;S<v.length;S++){const k=v[S];p(k)&&T(we,k.getAttribute(h),h,o,k)}}s&&s(w)}const A=[];if(e.indexOf("[")!==-1){const _=/\[([\w-]+)/g;let w;for(;(w=_.exec(e))!==null;)A.push(w[1])}else A.push(e);X({selector:e,attribute:t,componentTag:o,attributes:d,ComponentFn:n,onInit:s,observed:A.concat(i),onAttributeChange:l,onAttrChange:u,effects:f,declared:de,persist:ae}),Y();const fe=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";R().push({selector:e,attribute:t,ComponentFn:n,onInit:s,onSubtreeChange:c,query:fe}),ee(),window[t]=g;function F(){G()>0?J(function(){g(document.body)}):g(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",F):F(),g}function q(e){return(e||"").replace(/^#/,"")}function m(e){const t=e===void 0?location.hash:e,n={},o=q(t);if(!o)return n;const r=o.split("&");for(let i=0;i<r.length;i++){const l=r[i];if(!l)continue;const c=l.indexOf(":"),s=c>-1?l.slice(0,c):l,u=c>-1?l.slice(c+1):"";if(s)try{n[s]=decodeURIComponent(u)}catch{n[s]=u}}return n}function ne(e){if(!e)return null;const t=m();return e in t?t[e]:null}function oe(e,t){if(!e)return;const n=m();t==null?delete n[e]:n[e]=String(t);const r=Object.keys(n).map(function(i){const l=n[i];return l===""?i:i+":"+encodeURIComponent(l)}).join("&");q(location.hash)!==r&&(location.hash=r)}function re(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function ie(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const n=e.getAttribute("data-ln-hash");if(n&&n.trim()!=="")return n.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function le(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function se(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ce(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function ue(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const n=e.slice(0,t),o=e.slice(t+1),r=o?o.split(",").map(function(i){try{return decodeURIComponent(i)}catch{return i}}).filter(Boolean):[];return{key:n,values:r}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=m,window.lnCore.hashGet=ne,window.lnCore.hashSet=oe,window.lnCore.hashLinkClick=re,window.lnCore.resolveHashNamespace=ie,window.lnCore.hashSortEncode=le,window.lnCore.hashSortDecode=se,window.lnCore.hashFilterEncode=ce,window.lnCore.hashFilterDecode=ue),(function(){const e="data-ln-autoresize",t="lnAutoresize";if(window[t]!==void 0)return;const n={"data-ln-autoresize":{type:"marker",description:"Automatically adjusts textarea height to match its scrollable content"}};function o(r){if(r.tagName!=="TEXTAREA")return console.warn("[ln-autoresize] Can only be applied to <textarea>, got:",r.tagName),this;this.dom=r;const i=this;return this._onInput=function(){i._resize()},r.addEventListener("input",this._onInput),this._resize(),this}o.prototype._resize=function(){this.dom.style.height="auto",this.dom.style.height=this.dom.scrollHeight+"px"},o.prototype.destroy=function(){this.dom[t]&&(this.dom.removeEventListener("input",this._onInput),this.dom.style.height="",delete this.dom[t])},te(e,t,o,"ln-autoresize",{attributes:n})})()})();
@@ -0,0 +1,22 @@
1
+ {
2
+ "$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
3
+ "component": "ln-autoresize",
4
+ "generator": "scripts/sync-ln-schemas.mjs",
5
+ "attributes": {
6
+ "data-ln-autoresize": {
7
+ "direction": null,
8
+ "sources": [
9
+ "ln-autoresize-dev.scss",
10
+ "src/ln-autoresize.js"
11
+ ],
12
+ "type": "marker",
13
+ "description": "Automatically adjusts textarea height to match its scrollable content"
14
+ },
15
+ "data-ln-debug": {
16
+ "direction": null,
17
+ "sources": [
18
+ "ln-autoresize-dev.scss"
19
+ ]
20
+ }
21
+ }
22
+ }
@@ -6,6 +6,11 @@ import { registerComponent } from '../../ln-core';
6
6
 
7
7
  if (window[DOM_ATTRIBUTE] !== undefined) return;
8
8
 
9
+ // ─── Attribute Contract (SSOT) ──────────────────────────
10
+ const ATTRIBUTES = {
11
+ 'data-ln-autoresize': { type: 'marker', description: 'Automatically adjusts textarea height to match its scrollable content' }
12
+ };
13
+
9
14
  // ─── Component ─────────────────────────────────────────────
10
15
 
11
16
  function _component(dom) {
@@ -43,5 +48,7 @@ import { registerComponent } from '../../ln-core';
43
48
 
44
49
  // ─── Init ──────────────────────────────────────────────────
45
50
 
46
- registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-autoresize');
51
+ registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-autoresize', {
52
+ attributes: ATTRIBUTES
53
+ });
47
54
  })();