@livenetworks/ashlar 1.5.1 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/README.md +189 -177
  2. package/js/COMPONENTS.md +55 -49
  3. package/js/index.js +22 -5
  4. package/js/ln-accordion/README.md +186 -137
  5. package/js/ln-accordion/ln-accordion.js +1 -1
  6. package/js/ln-ajax/README.md +73 -4
  7. package/js/ln-ajax/ln-ajax.js +1 -1
  8. package/js/ln-ajax/src/ln-ajax.js +13 -13
  9. package/js/ln-api-connector/README.md +261 -150
  10. package/js/ln-api-connector/ln-api-connector.js +1 -1
  11. package/js/ln-api-connector/src/ln-api-connector.js +368 -265
  12. package/js/ln-api-queue/README.md +219 -0
  13. package/js/ln-api-queue/ln-api-queue.js +1 -0
  14. package/js/ln-api-queue/src/ln-api-queue.js +320 -0
  15. package/js/ln-api-queue/src/queue-storage.js +455 -0
  16. package/js/ln-autoresize/README.md +47 -0
  17. package/js/ln-autoresize/ln-autoresize.js +1 -1
  18. package/js/ln-autosave/README.md +33 -1
  19. package/js/ln-autosave/ln-autosave.js +1 -1
  20. package/js/ln-autosave/src/ln-autosave.js +4 -4
  21. package/js/ln-circular-progress/README.md +27 -13
  22. package/js/ln-circular-progress/ln-circular-progress.js +1 -1
  23. package/js/ln-circular-progress/src/ln-circular-progress.js +18 -5
  24. package/js/ln-confirm/README.md +165 -86
  25. package/js/ln-confirm/_ln-confirm.scss +11 -0
  26. package/js/ln-confirm/ln-confirm.js +1 -1
  27. package/js/ln-confirm/src/ln-confirm.js +82 -42
  28. package/js/ln-core/README.md +896 -0
  29. package/js/ln-core/hash.js +92 -0
  30. package/js/ln-core/helpers.js +337 -8
  31. package/js/ln-core/index.js +4 -2
  32. package/js/ln-core/persist.js +29 -3
  33. package/js/ln-core/positioning.js +1 -35
  34. package/js/ln-core/window-cache.js +213 -0
  35. package/js/ln-couchdb-connector/README.md +177 -156
  36. package/js/ln-couchdb-connector/ln-couchdb-connector.js +1 -1
  37. package/js/ln-couchdb-connector/src/ln-couchdb-connector.js +398 -348
  38. package/js/ln-data-coordinator/README.md +536 -165
  39. package/js/ln-data-coordinator/ln-data-coordinator.js +1 -1
  40. package/js/ln-data-coordinator/src/data-read-policy.js +18 -0
  41. package/js/ln-data-coordinator/src/ln-data-coordinator.js +1042 -249
  42. package/js/ln-data-coordinator/src/mutation-receipts.js +46 -0
  43. package/js/ln-data-store/README.md +241 -94
  44. package/js/ln-data-store/ln-data-store.js +1 -1
  45. package/js/ln-data-store/src/ln-data-store.js +694 -699
  46. package/js/ln-date/README.md +39 -1
  47. package/js/ln-date/ln-date-dev.scss +14 -0
  48. package/js/ln-date/ln-date.js +1 -1
  49. package/js/ln-date/src/ln-date.js +236 -178
  50. package/js/ln-debug/README.md +58 -0
  51. package/js/ln-debug/ln-debug.js +1 -0
  52. package/js/ln-debug/src/ln-debug.js +19 -0
  53. package/js/ln-dropdown/README.md +31 -8
  54. package/js/ln-dropdown/ln-dropdown.js +1 -1
  55. package/js/ln-dropdown/src/ln-dropdown.js +30 -13
  56. package/js/ln-editor/README.md +274 -0
  57. package/js/ln-editor/ln-editor.js +1 -0
  58. package/js/ln-editor/ln-editor.scss +43 -0
  59. package/js/ln-editor/src/ln-editor.js +619 -0
  60. package/js/ln-external-links/README.md +44 -5
  61. package/js/ln-external-links/ln-external-links.js +1 -1
  62. package/js/ln-fill/README.md +199 -0
  63. package/js/ln-fill/ln-fill.js +1 -0
  64. package/js/ln-fill/src/ln-fill.js +87 -0
  65. package/js/ln-filter/README.md +92 -2
  66. package/js/ln-filter/ln-filter-dev.scss +8 -0
  67. package/js/ln-filter/ln-filter.js +1 -1
  68. package/js/ln-filter/src/ln-filter.js +22 -7
  69. package/js/ln-form/README.md +212 -49
  70. package/js/ln-form/ln-form.js +1 -1
  71. package/js/ln-form/src/ln-form.js +99 -199
  72. package/js/ln-http/README.md +125 -89
  73. package/js/ln-http/ln-http.js +1 -1
  74. package/js/ln-http/src/ln-http.js +32 -13
  75. package/js/ln-icon/README.md +130 -0
  76. package/js/ln-icon/ln-icon.js +1 -0
  77. package/js/{ln-icons/src/ln-icons.js → ln-icon/src/ln-icon.js} +20 -15
  78. package/js/ln-link/README.md +47 -9
  79. package/js/ln-link/ln-link.js +1 -1
  80. package/js/ln-link/src/ln-link.js +22 -6
  81. package/js/ln-list/README.md +129 -0
  82. package/js/ln-list/ln-list.js +1 -0
  83. package/js/ln-list/ln-list.scss +28 -0
  84. package/js/ln-list/src/ln-list.js +1216 -0
  85. package/js/ln-modal/README.md +185 -154
  86. package/js/ln-modal/ln-modal-dev.scss +13 -0
  87. package/js/ln-modal/ln-modal.js +1 -1
  88. package/js/ln-modal/ln-modal.scss +28 -4
  89. package/js/ln-modal/src/ln-modal.js +137 -201
  90. package/js/ln-modal-coordinator/README.md +99 -0
  91. package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +8 -0
  92. package/js/ln-modal-coordinator/ln-modal-coordinator.js +1 -0
  93. package/js/ln-modal-coordinator/src/ln-modal-coordinator.js +345 -0
  94. package/js/ln-nav/README.md +46 -3
  95. package/js/ln-nav/ln-nav.js +1 -1
  96. package/js/ln-nav/src/ln-nav.js +92 -127
  97. package/js/ln-number/README.md +28 -1
  98. package/js/ln-number/ln-number-dev.scss +13 -0
  99. package/js/ln-number/ln-number.js +1 -1
  100. package/js/ln-number/src/ln-number.js +443 -350
  101. package/js/ln-options/README.md +66 -0
  102. package/js/ln-options/ln-options.js +1 -0
  103. package/js/ln-options/src/ln-options.js +74 -0
  104. package/js/ln-popover/README.md +40 -5
  105. package/js/ln-popover/ln-popover.js +1 -1
  106. package/js/ln-popover/src/ln-popover.js +38 -11
  107. package/js/ln-progress/README.md +413 -442
  108. package/js/ln-progress/ln-progress.js +1 -1
  109. package/js/ln-progress/src/ln-progress.js +98 -150
  110. package/js/ln-router/README.md +432 -0
  111. package/js/ln-router/ln-router.js +1 -0
  112. package/js/ln-router/src/ln-router.js +539 -0
  113. package/js/ln-search/README.md +158 -83
  114. package/js/ln-search/ln-search-dev.scss +8 -0
  115. package/js/ln-search/ln-search.js +1 -1
  116. package/js/ln-search/src/ln-search.js +12 -9
  117. package/js/ln-slug/README.md +110 -0
  118. package/js/ln-slug/ln-slug.js +1 -0
  119. package/js/ln-slug/src/ln-slug.js +74 -0
  120. package/js/ln-sort/README.md +170 -0
  121. package/js/ln-sort/ln-sort-dev.scss +8 -0
  122. package/js/ln-sort/ln-sort.js +1 -0
  123. package/js/ln-sort/src/ln-sort.js +178 -0
  124. package/js/ln-sortable/README.md +133 -95
  125. package/js/ln-sortable/ln-sortable.js +1 -1
  126. package/js/ln-stat/README.md +55 -0
  127. package/js/ln-stat/ln-stat.js +1 -0
  128. package/js/ln-stat/src/ln-stat.js +55 -0
  129. package/js/ln-table/README.md +285 -101
  130. package/js/ln-table/ln-table-dev.scss +17 -0
  131. package/js/ln-table/ln-table.js +1 -1
  132. package/js/ln-table/ln-table.scss +1 -1
  133. package/js/ln-table/src/ln-table.js +1493 -473
  134. package/js/ln-table-coordinator/README.md +73 -0
  135. package/js/ln-table-coordinator/ln-table-coordinator.js +1 -0
  136. package/js/ln-table-coordinator/src/ln-table-coordinator.js +160 -0
  137. package/js/ln-tabs/README.md +221 -137
  138. package/js/ln-tabs/ln-tabs-dev.scss +18 -0
  139. package/js/ln-tabs/ln-tabs.js +1 -1
  140. package/js/ln-tabs/src/ln-tabs.js +41 -24
  141. package/js/ln-time/README.md +14 -0
  142. package/js/ln-time/ln-time.js +1 -1
  143. package/js/ln-time/src/ln-time.js +223 -192
  144. package/js/ln-toast/README.md +178 -122
  145. package/js/ln-toast/ln-toast.js +1 -15
  146. package/js/ln-toast/src/ln-toast.js +232 -210
  147. package/js/ln-toast/template.html +16 -12
  148. package/js/ln-toggle/README.md +61 -2
  149. package/js/ln-toggle/ln-toggle-dev.scss +13 -0
  150. package/js/ln-toggle/ln-toggle.js +1 -1
  151. package/js/ln-toggle/src/ln-toggle.js +56 -43
  152. package/js/ln-tooltip/README.md +95 -58
  153. package/js/ln-tooltip/ln-tooltip-dev.scss +9 -0
  154. package/js/ln-tooltip/ln-tooltip.js +1 -1
  155. package/js/ln-tooltip/src/ln-tooltip.js +45 -6
  156. package/js/ln-translations/README.md +118 -96
  157. package/js/ln-translations/ln-translations.js +1 -1
  158. package/js/ln-translations/src/ln-translations.js +10 -5
  159. package/js/ln-upload/README.md +85 -10
  160. package/js/ln-upload/ln-upload.js +1 -1
  161. package/js/ln-upload/src/ln-upload.js +26 -10
  162. package/js/ln-validate/README.md +72 -0
  163. package/js/ln-validate/ln-validate-dev.scss +15 -0
  164. package/js/ln-validate/ln-validate.js +1 -1
  165. package/js/ln-validate/src/ln-validate.js +64 -0
  166. package/package.json +61 -56
  167. package/scss/base/_global.scss +2 -2
  168. package/scss/base/_typography.scss +1 -2
  169. package/scss/components/_date.scss +1 -0
  170. package/scss/components/_dropdown.scss +0 -5
  171. package/scss/components/_editor.scss +5 -0
  172. package/scss/components/_filter.scss +26 -25
  173. package/scss/components/_form.scss +7 -0
  174. package/scss/components/_ln-table.scss +13 -3
  175. package/scss/components/_sort.scss +10 -0
  176. package/scss/components/_table.scss +36 -23
  177. package/scss/components/_toast.scss +68 -41
  178. package/scss/components/_toggle.scss +16 -0
  179. package/scss/config/_density.scss +205 -117
  180. package/scss/config/_icons.scss +10 -9
  181. package/scss/config/_tokens.scss +69 -47
  182. package/scss/config/mixins/_accordion.scss +2 -7
  183. package/scss/config/mixins/_alert.scss +4 -4
  184. package/scss/config/mixins/_breadcrumbs.scss +2 -2
  185. package/scss/config/mixins/_btn.scss +1 -1
  186. package/scss/config/mixins/_card.scss +89 -14
  187. package/scss/config/mixins/_collapsible.scss +3 -0
  188. package/scss/config/mixins/_colors.scss +1 -1
  189. package/scss/config/mixins/_diagnostics.scss +11 -0
  190. package/scss/config/mixins/_display.scss +1 -0
  191. package/scss/config/mixins/_dropdown.scss +3 -5
  192. package/scss/config/mixins/_editor.scss +124 -0
  193. package/scss/config/mixins/_empty-state.scss +7 -0
  194. package/scss/config/mixins/_filter.scss +3 -5
  195. package/scss/config/mixins/_footer.scss +1 -2
  196. package/scss/config/mixins/_form.scss +207 -21
  197. package/scss/config/mixins/_index.scss +2 -0
  198. package/scss/config/mixins/_ln-table.scss +41 -2
  199. package/scss/config/mixins/_modal.scss +149 -66
  200. package/scss/config/mixins/_nav.scss +3 -4
  201. package/scss/config/mixins/_popover.scss +39 -0
  202. package/scss/config/mixins/_sidebar.scss +1 -1
  203. package/scss/config/mixins/_sort.scss +42 -0
  204. package/scss/config/mixins/_table.scss +85 -60
  205. package/scss/config/mixins/_toast.scss +179 -152
  206. package/scss/config/mixins/_tooltip.scss +17 -7
  207. package/scss/config/mixins/_typography.scss +4 -2
  208. package/scss/ln-ashlar-dev.scss +27 -9
  209. package/scss/ln-ashlar.scss +7 -1
  210. package/js/ln-data-table/README.md +0 -110
  211. package/js/ln-data-table/ln-data-table.js +0 -1
  212. package/js/ln-data-table/ln-data-table.scss +0 -10
  213. package/js/ln-data-table/src/ln-data-table.js +0 -1087
  214. package/js/ln-icons/README.md +0 -88
  215. package/js/ln-icons/ln-icons.js +0 -1
  216. package/js/ln-table/ln-table-sort.js +0 -1
  217. package/js/ln-table/src/ln-table-sort.js +0 -156
@@ -1,88 +0,0 @@
1
- # ln-icons
2
-
3
- A zero-dependency, local-first **On-Demand SVG Sprite Generator** that dynamically monitors, fetches, and compiles SVG icons at runtime.
4
-
5
- Instead of bundling thousands of heavy vector paths or requiring complex manual build steps, it intercepts standard DOM `<use>` tags, fetches vector definitions from a remote CDN, caches them in `localStorage`, and injects them into a single unified hidden SVG sprite sheet.
6
-
7
- ---
8
-
9
- ## 🧭 Philosophy & Architecture
10
-
11
- 1. **Declarative On-Demand Rendering:** Icons are declared directly in HTML. The component monitors the DOM via `MutationObserver` for `<use>` references with `#ln-` and `#lnc-` prefixes. It only fetches and compiles icons that are actively present on the page.
12
- 2. **Dual-Prefix Routing:**
13
- - **`#ln-{name}`**: Automatically routes to the [Tabler Icons](https://tabler.io/icons) library fetched from a public CDN. No configuration required.
14
- - **`#lnc-{name}`**: Routes to a custom corporate CDN defined via global window settings.
15
- 3. **Local Caching Layer:** Fetched SVG path structures are instantly cached in `localStorage` under `lni:{id}`. Subsequent visits render icons instantly with zero network roundtrips.
16
-
17
- ---
18
-
19
- ## 📦 Minimal Blueprint
20
-
21
- ### Native Tabler Icon
22
- ```html
23
- <svg class="ln-icon" aria-hidden="true">
24
- <use href="#ln-home"></use>
25
- </svg>
26
- ```
27
-
28
- ### Custom Asset Icon
29
- Define your custom CDN endpoint before importing the library:
30
- ```html
31
- <script>
32
- window.LN_ICONS_CUSTOM_CDN = "https://cdn.mycompany.com/assets/icons";
33
- </script>
34
- <script src="dist/ln-ashlar.iife.js" defer></script>
35
-
36
- <!-- Renders icon from your custom CDN -->
37
- <svg class="ln-icon" aria-hidden="true">
38
- <use href="#lnc-corporate-logo"></use>
39
- </svg>
40
- ```
41
-
42
- ---
43
-
44
- ## 🛠️ Declarative API Contract
45
-
46
- ### CSS Utility Classes
47
-
48
- Configure icon sizes and alignments using standard CSS classes:
49
-
50
- | Class | Size | Description |
51
- | :--- | :--- | :--- |
52
- | `ln-icon` | `1.25rem` | Base styles, sets `fill: none`, `stroke: currentColor`, inherits color. |
53
- | `ln-icon--sm` | `1rem` | Small icon, designed for inline text badges or buttons. |
54
- | `ln-icon--lg` | `1.5rem` | Large icon, designed for toolbar buttons. |
55
- | `ln-icon--xl` | `4rem` | Extra-large icon, designed for empty state illustrations. |
56
- | `ln-chevron` | — | Automatically rotates `90deg` when an ancestor `.is-active` class is toggled. |
57
-
58
- ### Global Configuration (`window`)
59
-
60
- Configure these properties before script initialization:
61
-
62
- | Variable | Default | Description |
63
- | :--- | :--- | :--- |
64
- | `LN_ICONS_CDN` | `https://cdn.jsdelivr.net/npm/@tabler/icons@3.31.0/icons/outline` | Base CDN URL for Tabler Icons. |
65
- | `LN_ICONS_CUSTOM_CDN` | `null` | Base CDN URL for custom `#lnc-` prefixed SVG resources. |
66
-
67
- ---
68
-
69
- ## ⚡ Dynamic Interaction Flow
70
-
71
- ### Automated Mutation Observability
72
- The loader observes the DOM continuously. When new content is injected (e.g. by `ln-ajax` or `ln-store`), any new icon `<use>` tag is intercepted, resolved, and rendered.
73
-
74
- ### Dynamic Attribute Swaps
75
- Modifying the `href` attribute of a `<use>` element dynamically via JavaScript triggers automatic resolution of the new target icon:
76
- ```javascript
77
- const useElement = document.querySelector('use');
78
- // Dynamically fetches and switches the icon to a checkmark
79
- useElement.setAttribute('href', '#ln-check');
80
- ```
81
-
82
- ---
83
-
84
- ## ⚠️ Common Pitfalls
85
-
86
- - **Forgetting `ln-icon` Class:** Standard SVGs default to `100%` width/height. Failing to include the `ln-icon` class will cause the icon to blow up to full viewport size.
87
- - **Incorrect Prefix Configuration:** Forgetting to define `window.LN_ICONS_CUSTOM_CDN` when using `#lnc-` will cause the loader to fail silently with undefined endpoint errors.
88
- - **Omitting `aria-hidden="true"`:** Screen readers attempt to read SVG nodes. Always decorate decorative icons with `aria-hidden="true"`, or include an `aria-label` on their parent button.
@@ -1 +0,0 @@
1
- (function(){"use strict";(function(){const h="ln-icons-sprite",a="#ln-",o="#lnc-",d=new Set,l=new Set;let c=null;const C=(window.LN_ICONS_CDN||"https://cdn.jsdelivr.net/npm/@tabler/icons@3.31.0/icons/outline").replace(/\/$/,""),g=(window.LN_ICONS_CUSTOM_CDN||"").replace(/\/$/,""),u="lni:",m="lni:v",S="1";function v(){try{if(localStorage.getItem(m)!==S){for(let t=localStorage.length-1;t>=0;t--){const n=localStorage.key(t);n&&n.indexOf(u)===0&&localStorage.removeItem(n)}localStorage.setItem(m,S)}}catch{}}v();function N(){return c||(c=document.getElementById(h),c||(c=document.createElementNS("http://www.w3.org/2000/svg","svg"),c.id=h,c.setAttribute("hidden",""),c.setAttribute("aria-hidden","true"),c.appendChild(document.createElementNS("http://www.w3.org/2000/svg","defs")),document.body.insertBefore(c,document.body.firstChild))),c}function A(t){return t.indexOf(o)===0?g+"/"+t.slice(o.length)+".svg":C+"/"+t.slice(a.length)+".svg"}function w(t,n){const e=n.match(/viewBox="([^"]+)"/),i=e?e[1]:"0 0 24 24",s=n.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i),I=s?s[1].trim():"",y=n.match(/<svg([^>]*)>/i),O=y?y[1]:"",r=document.createElementNS("http://www.w3.org/2000/svg","symbol");r.id=t,r.setAttribute("viewBox",i),["fill","stroke","stroke-width","stroke-linecap","stroke-linejoin"].forEach(function(_){const b=O.match(new RegExp(_+'="([^"]*)"'));b&&r.setAttribute(_,b[1])}),r.innerHTML=I,N().querySelector("defs").appendChild(r)}function f(t){if(d.has(t)||l.has(t)||t.indexOf(o)===0&&!g)return;const n=t.slice(1);try{const e=localStorage.getItem(u+n);if(e){w(n,e),d.add(t);return}}catch{}l.add(t),fetch(A(t)).then(function(e){if(!e.ok)throw new Error(e.status);return e.text()}).then(function(e){w(n,e),d.add(t),l.delete(t);try{localStorage.setItem(u+n,e)}catch{}}).catch(function(){l.delete(t)})}function E(t){const n='use[href^="'+a+'"], use[href^="'+o+'"]',e=t.querySelectorAll?t.querySelectorAll(n):[];if(t.matches&&t.matches(n)){const i=t.getAttribute("href");i&&f(i)}Array.prototype.forEach.call(e,function(i){const s=i.getAttribute("href");s&&f(s)})}function p(){E(document),new MutationObserver(function(t){t.forEach(function(n){if(n.type==="childList")n.addedNodes.forEach(function(e){e.nodeType===1&&E(e)});else if(n.type==="attributes"&&n.attributeName==="href"){const e=n.target.getAttribute("href");e&&(e.indexOf(a)===0||e.indexOf(o)===0)&&f(e)}})}).observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]})}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",p):p()})()})();
@@ -1 +0,0 @@
1
- (function(){"use strict";function y(t,e,s){t.dispatchEvent(new CustomEvent(e,{bubbles:!0,detail:s||{}}))}function f(t,e){if(!document.body){document.addEventListener("DOMContentLoaded",function(){f(t,e)}),console.warn("["+e+'] Script loaded before <body> — add "defer" to your <script> tag');return}t()}const h={};function _(t,e){h[t]=e}function w(t){return h[t]||{ingress:e=>e,egress:e=>e}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=_,window.lnCore.getDataMapper=w);const g="ln:";function S(){return location.pathname.replace(/\/+$/,"").toLowerCase()||"/"}function p(t,e){const s=e.getAttribute("data-ln-persist"),l=s!==null&&s!==""?s:e.id;return l?g+t+":"+S()+":"+l:(console.warn('[ln-persist] Element requires id or data-ln-persist="key"',e),null)}function m(t,e){const s=p(t,e);if(!s)return null;try{const l=localStorage.getItem(s);return l!==null?JSON.parse(l):null}catch{return null}}function b(t,e,s){const l=p(t,e);if(l)try{localStorage.setItem(l,JSON.stringify(s))}catch{}}(function(){const t="lnTableSort",e="data-ln-sort",s="data-ln-table-sort";if(window[t]!==void 0)return;function l(o){a(o)}function a(o){const r=Array.from(o.querySelectorAll("table"));o.tagName==="TABLE"&&r.push(o),r.forEach(function(n){if(n[t])return;const c=Array.from(n.querySelectorAll("th["+e+"]"));c.length&&(n[t]=new u(n,c))})}function u(o,r){this.table=o,this.ths=r,this._col=-1,this._dir=null;const n=this;r.forEach(function(i,E){if(i[t+"Bound"])return;i[t+"Bound"]=!0;const d=i.querySelector("["+s+"]");d&&(d._lnSortClick=function(){n._handleClick(E,i)},d.addEventListener("click",d._lnSortClick))});const c=o.closest("[data-ln-table][data-ln-persist]");if(c){const i=m("table-sort",c);i&&i.dir&&i.col>=0&&i.col<r.length&&(this._handleClick(i.col,r[i.col]),i.dir==="desc"&&this._handleClick(i.col,r[i.col]))}return this}u.prototype._handleClick=function(o,r){let n;this._col!==o?n="asc":this._dir==="asc"?n="desc":this._dir==="desc"?n=null:n="asc",this.ths.forEach(function(i){i.classList.remove("ln-sort-asc","ln-sort-desc")}),n===null?(this._col=-1,this._dir=null):(this._col=o,this._dir=n,r.classList.add(n==="asc"?"ln-sort-asc":"ln-sort-desc")),y(this.table,"ln-table:sort",{column:o,sortType:r.getAttribute(e),direction:n});const c=this.table.closest("[data-ln-table][data-ln-persist]");c&&(n===null?b("table-sort",c,null):b("table-sort",c,{col:o,dir:n}))},u.prototype.destroy=function(){this.table[t]&&(this.ths.forEach(function(o){const r=o.querySelector("["+s+"]");r&&r._lnSortClick&&(r.removeEventListener("click",r._lnSortClick),delete r._lnSortClick),delete o[t+"Bound"]}),delete this.table[t])};function C(){f(function(){new MutationObserver(function(r){r.forEach(function(n){n.type==="childList"?n.addedNodes.forEach(function(c){c.nodeType===1&&a(c)}):n.type==="attributes"&&a(n.target)})}).observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:[e]})},"ln-table-sort")}window[t]=l,C(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){l(document.body)}):l(document.body)})()})();
@@ -1,156 +0,0 @@
1
- import { guardBody, dispatch } from '../../ln-core';
2
- import { persistGet, persistSet } from '../../ln-core';
3
-
4
- (function () {
5
- const DOM_ATTRIBUTE = 'lnTableSort';
6
- const SORT_ATTR = 'data-ln-sort';
7
- const BUTTON_HOOK = 'data-ln-table-sort';
8
-
9
- if (window[DOM_ATTRIBUTE] !== undefined) return;
10
-
11
- // ─── Constructor ───────────────────────────────────────────
12
- // Auto-initializes any <table> that contains th[data-ln-sort] headers.
13
-
14
- function constructor(domRoot) {
15
- findElements(domRoot);
16
- }
17
-
18
- // Local findElements — intentional divergence from ln-core helper: tag selector ('table') + two-arg constructor (table, ths).
19
- function findElements(root) {
20
- const tables = Array.from(root.querySelectorAll('table'));
21
- if (root.tagName === 'TABLE') tables.push(root);
22
-
23
- tables.forEach(function (table) {
24
- if (table[DOM_ATTRIBUTE]) return;
25
- const ths = Array.from(table.querySelectorAll('th[' + SORT_ATTR + ']'));
26
- if (ths.length) table[DOM_ATTRIBUTE] = new _component(table, ths);
27
- });
28
- }
29
-
30
- // ─── Component ─────────────────────────────────────────────
31
-
32
- function _component(table, ths) {
33
- this.table = table;
34
- this.ths = ths;
35
- this._col = -1;
36
- this._dir = null;
37
- const self = this;
38
-
39
- ths.forEach(function (th, index) {
40
- if (th[DOM_ATTRIBUTE + 'Bound']) return;
41
- th[DOM_ATTRIBUTE + 'Bound'] = true;
42
-
43
- // D1/Option A: bind click to the sort button, not the whole <th>.
44
- // Columns without a [data-ln-table-sort] button skip binding.
45
- const btn = th.querySelector('[' + BUTTON_HOOK + ']');
46
- if (!btn) return;
47
-
48
- btn._lnSortClick = function () {
49
- self._handleClick(index, th);
50
- };
51
- btn.addEventListener('click', btn._lnSortClick);
52
- });
53
-
54
- // ─── Restore persisted sort ───────────────────────────────
55
- const persistRoot = table.closest('[data-ln-table][data-ln-persist]');
56
- if (persistRoot) {
57
- const saved = persistGet('table-sort', persistRoot);
58
- if (saved && saved.dir && saved.col >= 0 && saved.col < ths.length) {
59
- // Programmatically trigger the saved sort
60
- this._handleClick(saved.col, ths[saved.col]);
61
- if (saved.dir === 'desc') {
62
- this._handleClick(saved.col, ths[saved.col]);
63
- }
64
- }
65
- }
66
-
67
- return this;
68
- }
69
-
70
- _component.prototype._handleClick = function (colIndex, th) {
71
- let newDir;
72
-
73
- if (this._col !== colIndex) {
74
- newDir = 'asc';
75
- } else if (this._dir === 'asc') {
76
- newDir = 'desc';
77
- } else if (this._dir === 'desc') {
78
- newDir = null;
79
- } else {
80
- newDir = 'asc';
81
- }
82
-
83
- // JS-2: use state classes on <th>; CSS owns icon visibility.
84
- this.ths.forEach(function (t) {
85
- t.classList.remove('ln-sort-asc', 'ln-sort-desc');
86
- });
87
-
88
- if (newDir === null) {
89
- this._col = -1;
90
- this._dir = null;
91
- } else {
92
- this._col = colIndex;
93
- this._dir = newDir;
94
- th.classList.add(newDir === 'asc' ? 'ln-sort-asc' : 'ln-sort-desc');
95
- }
96
-
97
- dispatch(this.table, 'ln-table:sort', {
98
- column: colIndex,
99
- sortType: th.getAttribute(SORT_ATTR),
100
- direction: newDir
101
- });
102
- const persistRoot = this.table.closest('[data-ln-table][data-ln-persist]');
103
- if (persistRoot) {
104
- if (newDir === null) {
105
- persistSet('table-sort', persistRoot, null);
106
- } else {
107
- persistSet('table-sort', persistRoot, { col: colIndex, dir: newDir });
108
- }
109
- }
110
- };
111
-
112
- _component.prototype.destroy = function () {
113
- if (!this.table[DOM_ATTRIBUTE]) return;
114
- this.ths.forEach(function (th) {
115
- const btn = th.querySelector('[' + BUTTON_HOOK + ']');
116
- if (btn && btn._lnSortClick) {
117
- btn.removeEventListener('click', btn._lnSortClick);
118
- delete btn._lnSortClick;
119
- }
120
- delete th[DOM_ATTRIBUTE + 'Bound'];
121
- });
122
- delete this.table[DOM_ATTRIBUTE];
123
- };
124
-
125
- // ─── DOM Observer ──────────────────────────────────────────
126
-
127
- function _domObserver() {
128
- guardBody(function () {
129
- const observer = new MutationObserver(function (mutations) {
130
- mutations.forEach(function (mutation) {
131
- if (mutation.type === 'childList') {
132
- mutation.addedNodes.forEach(function (node) {
133
- if (node.nodeType === 1) findElements(node);
134
- });
135
- } else if (mutation.type === 'attributes') {
136
- findElements(mutation.target);
137
- }
138
- });
139
- });
140
- observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: [SORT_ATTR] });
141
- }, 'ln-table-sort');
142
- }
143
-
144
- // ─── Init ──────────────────────────────────────────────────
145
-
146
- window[DOM_ATTRIBUTE] = constructor;
147
- _domObserver();
148
-
149
- if (document.readyState === 'loading') {
150
- document.addEventListener('DOMContentLoaded', function () {
151
- constructor(document.body);
152
- });
153
- } else {
154
- constructor(document.body);
155
- }
156
- })();