ngwr 8.0.0 → 9.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 (431) hide show
  1. package/README.md +75 -28
  2. package/action-sheet/styles/_index.scss +93 -0
  3. package/alert/styles/_index.scss +10 -10
  4. package/anchor/styles/_index.scss +3 -3
  5. package/back-top/styles/_index.scss +1 -1
  6. package/badge/styles/_tag.scss +3 -3
  7. package/bar-chart/styles/_index.scss +4 -4
  8. package/border-glow/styles/_index.scss +3 -3
  9. package/breadcrumbs/styles/_index.scss +3 -3
  10. package/burger/styles/_index.scss +1 -1
  11. package/button/styles/_index.scss +4 -4
  12. package/calendar/styles/_index.scss +4 -4
  13. package/calendar-heatmap/styles/_index.scss +3 -3
  14. package/card/styles/_index.scss +5 -5
  15. package/carousel/styles/_index.scss +5 -5
  16. package/cascader/styles/_index.scss +15 -15
  17. package/checkbox/styles/_index.scss +20 -5
  18. package/collapse/styles/_index.scss +6 -6
  19. package/color-picker/styles/_index.scss +15 -9
  20. package/command-palette/styles/_index.scss +19 -16
  21. package/compare/styles/_index.scss +3 -3
  22. package/context-menu/styles/_index.scss +16 -6
  23. package/counter/styles/_index.scss +12 -1
  24. package/date-picker/styles/_index.scss +8 -8
  25. package/descriptions/styles/_index.scss +9 -9
  26. package/dialog/styles/_index.scss +7 -6
  27. package/divider/styles/_index.scss +2 -2
  28. package/donut-chart/styles/_index.scss +3 -3
  29. package/drag-drop/styles/_index.scss +11 -6
  30. package/drawer/styles/_index.scss +15 -6
  31. package/dropdown/styles/_index.scss +5 -5
  32. package/empty/styles/_index.scss +4 -4
  33. package/fesm2022/ngwr-action-sheet.mjs +81 -0
  34. package/fesm2022/ngwr-action-sheet.mjs.map +1 -0
  35. package/fesm2022/ngwr-affix.mjs +3 -3
  36. package/fesm2022/ngwr-alert.mjs +4 -4
  37. package/fesm2022/ngwr-alert.mjs.map +1 -1
  38. package/fesm2022/ngwr-anchor.mjs +4 -4
  39. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  40. package/fesm2022/ngwr-aurora.mjs +5 -4
  41. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  42. package/fesm2022/ngwr-avatar.mjs +4 -4
  43. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  44. package/fesm2022/ngwr-back-top.mjs +4 -4
  45. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  46. package/fesm2022/ngwr-badge.mjs +8 -8
  47. package/fesm2022/ngwr-badge.mjs.map +1 -1
  48. package/fesm2022/ngwr-bar-chart.mjs +4 -4
  49. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  50. package/fesm2022/ngwr-blur-text.mjs +3 -3
  51. package/fesm2022/ngwr-border-glow.mjs +4 -4
  52. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  53. package/fesm2022/ngwr-breadcrumbs.mjs +8 -8
  54. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  55. package/fesm2022/ngwr-burger.mjs +4 -4
  56. package/fesm2022/ngwr-burger.mjs.map +1 -1
  57. package/fesm2022/ngwr-button.mjs +8 -8
  58. package/fesm2022/ngwr-button.mjs.map +1 -1
  59. package/fesm2022/ngwr-calendar-heatmap.mjs +4 -4
  60. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  61. package/fesm2022/ngwr-calendar.mjs +4 -4
  62. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  63. package/fesm2022/ngwr-card.mjs +11 -11
  64. package/fesm2022/ngwr-card.mjs.map +1 -1
  65. package/fesm2022/ngwr-carousel.mjs +7 -7
  66. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  67. package/fesm2022/ngwr-cascader.mjs +52 -60
  68. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  69. package/fesm2022/ngwr-checkbox.mjs +74 -106
  70. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  71. package/fesm2022/ngwr-circular-text.mjs +5 -4
  72. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  73. package/fesm2022/ngwr-click-spark.mjs +5 -4
  74. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  75. package/fesm2022/ngwr-clipboard.mjs +4 -4
  76. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  77. package/fesm2022/ngwr-collapse.mjs +12 -12
  78. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  79. package/fesm2022/ngwr-color-picker.mjs +58 -66
  80. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  81. package/fesm2022/ngwr-command-palette.mjs +4 -4
  82. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  83. package/fesm2022/ngwr-compare.mjs +4 -4
  84. package/fesm2022/ngwr-compare.mjs.map +1 -1
  85. package/fesm2022/ngwr-confetti.mjs +3 -3
  86. package/fesm2022/ngwr-context-menu.mjs +86 -15
  87. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  88. package/fesm2022/ngwr-cookie.mjs +19 -6
  89. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  90. package/fesm2022/ngwr-counter.mjs +26 -12
  91. package/fesm2022/ngwr-counter.mjs.map +1 -1
  92. package/fesm2022/ngwr-date-adapter-fns.mjs +3 -3
  93. package/fesm2022/ngwr-date-adapter-luxon.mjs +3 -3
  94. package/fesm2022/ngwr-date-adapter.mjs +10 -5
  95. package/fesm2022/ngwr-date-adapter.mjs.map +1 -1
  96. package/fesm2022/ngwr-date-picker.mjs +128 -123
  97. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  98. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  99. package/fesm2022/ngwr-density.mjs +7 -7
  100. package/fesm2022/ngwr-density.mjs.map +1 -1
  101. package/fesm2022/ngwr-descriptions.mjs +7 -7
  102. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  103. package/fesm2022/ngwr-dialog.mjs +16 -16
  104. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  105. package/fesm2022/ngwr-directives.mjs +21 -15
  106. package/fesm2022/ngwr-directives.mjs.map +1 -1
  107. package/fesm2022/ngwr-divider.mjs +4 -4
  108. package/fesm2022/ngwr-divider.mjs.map +1 -1
  109. package/fesm2022/ngwr-donut-chart.mjs +4 -4
  110. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  111. package/fesm2022/ngwr-drag-drop.mjs +10 -9
  112. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  113. package/fesm2022/ngwr-drawer.mjs +19 -18
  114. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  115. package/fesm2022/ngwr-dropdown.mjs +13 -12
  116. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  117. package/fesm2022/ngwr-empty.mjs +4 -4
  118. package/fesm2022/ngwr-empty.mjs.map +1 -1
  119. package/fesm2022/ngwr-falling-text.mjs +5 -4
  120. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  121. package/fesm2022/ngwr-file-upload.mjs +58 -60
  122. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  123. package/fesm2022/ngwr-form.mjs +11 -11
  124. package/fesm2022/ngwr-form.mjs.map +1 -1
  125. package/fesm2022/ngwr-fuzzy-text.mjs +5 -4
  126. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  127. package/fesm2022/ngwr-gauge.mjs +4 -4
  128. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  129. package/fesm2022/ngwr-glitch-text.mjs +4 -4
  130. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  131. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  132. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  133. package/fesm2022/ngwr-hotkey.mjs +7 -7
  134. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  135. package/fesm2022/ngwr-i18n.mjs +10 -10
  136. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  137. package/fesm2022/ngwr-icon-adapters-lucide.mjs +6 -7
  138. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  139. package/fesm2022/ngwr-icon.mjs +4 -4
  140. package/fesm2022/ngwr-icon.mjs.map +1 -1
  141. package/fesm2022/ngwr-image-cropper.mjs +6 -5
  142. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  143. package/fesm2022/ngwr-input-number.mjs +56 -73
  144. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  145. package/fesm2022/ngwr-input-otp.mjs +46 -52
  146. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  147. package/fesm2022/ngwr-input.mjs +17 -17
  148. package/fesm2022/ngwr-input.mjs.map +1 -1
  149. package/fesm2022/ngwr-keyboard.mjs +4 -4
  150. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  151. package/fesm2022/ngwr-knob.mjs +47 -58
  152. package/fesm2022/ngwr-knob.mjs.map +1 -1
  153. package/fesm2022/ngwr-layout.mjs +16 -16
  154. package/fesm2022/ngwr-layout.mjs.map +1 -1
  155. package/fesm2022/ngwr-lightbox.mjs +7 -6
  156. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  157. package/fesm2022/ngwr-line-chart.mjs +4 -4
  158. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  159. package/fesm2022/ngwr-list.mjs +8 -8
  160. package/fesm2022/ngwr-list.mjs.map +1 -1
  161. package/fesm2022/ngwr-loading-bar.mjs +7 -7
  162. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  163. package/fesm2022/ngwr-marquee.mjs +6 -5
  164. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  165. package/fesm2022/ngwr-media.mjs +4 -4
  166. package/fesm2022/ngwr-media.mjs.map +1 -1
  167. package/fesm2022/ngwr-mention.mjs +15 -9
  168. package/fesm2022/ngwr-mention.mjs.map +1 -1
  169. package/fesm2022/ngwr-meta.mjs +7 -7
  170. package/fesm2022/ngwr-meta.mjs.map +1 -1
  171. package/fesm2022/ngwr-meter-group.mjs +4 -4
  172. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  173. package/fesm2022/ngwr-overlay.mjs +9 -4
  174. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  175. package/fesm2022/ngwr-page-header.mjs +4 -4
  176. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  177. package/fesm2022/ngwr-pagination.mjs +4 -4
  178. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  179. package/fesm2022/ngwr-pipes.mjs +21 -21
  180. package/fesm2022/ngwr-platform.mjs +169 -5
  181. package/fesm2022/ngwr-platform.mjs.map +1 -1
  182. package/fesm2022/ngwr-popconfirm.mjs +7 -7
  183. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  184. package/fesm2022/ngwr-popover.mjs +7 -7
  185. package/fesm2022/ngwr-popover.mjs.map +1 -1
  186. package/fesm2022/ngwr-progress.mjs +4 -4
  187. package/fesm2022/ngwr-progress.mjs.map +1 -1
  188. package/fesm2022/ngwr-pull-to-refresh.mjs +172 -0
  189. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -0
  190. package/fesm2022/ngwr-qr.mjs +5 -5
  191. package/fesm2022/ngwr-qr.mjs.map +1 -1
  192. package/fesm2022/ngwr-radio.mjs +27 -52
  193. package/fesm2022/ngwr-radio.mjs.map +1 -1
  194. package/fesm2022/ngwr-rating.mjs +35 -48
  195. package/fesm2022/ngwr-rating.mjs.map +1 -1
  196. package/fesm2022/ngwr-result.mjs +13 -13
  197. package/fesm2022/ngwr-result.mjs.map +1 -1
  198. package/fesm2022/ngwr-rotating-text.mjs +15 -4
  199. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  200. package/fesm2022/ngwr-scroll.mjs +4 -4
  201. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  202. package/fesm2022/ngwr-segmented.mjs +3 -3
  203. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  204. package/fesm2022/ngwr-select.mjs +289 -85
  205. package/fesm2022/ngwr-select.mjs.map +1 -1
  206. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  207. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  208. package/fesm2022/ngwr-sidebar.mjs +4 -4
  209. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  210. package/fesm2022/ngwr-skeleton.mjs +4 -4
  211. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  212. package/fesm2022/ngwr-slider.mjs +79 -73
  213. package/fesm2022/ngwr-slider.mjs.map +1 -1
  214. package/fesm2022/ngwr-sparkline.mjs +4 -4
  215. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  216. package/fesm2022/ngwr-speed-dial.mjs +13 -5
  217. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  218. package/fesm2022/ngwr-spinner.mjs +4 -4
  219. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  220. package/fesm2022/ngwr-splash-cursor.mjs +4 -4
  221. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  222. package/fesm2022/ngwr-split-text.mjs +3 -3
  223. package/fesm2022/ngwr-splitter.mjs +4 -4
  224. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  225. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  226. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  227. package/fesm2022/ngwr-squircle.mjs +7 -7
  228. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  229. package/fesm2022/ngwr-star-border.mjs +4 -4
  230. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  231. package/fesm2022/ngwr-statistic.mjs +65 -10
  232. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  233. package/fesm2022/ngwr-stepper.mjs +8 -8
  234. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  235. package/fesm2022/ngwr-storage.mjs +4 -4
  236. package/fesm2022/ngwr-storage.mjs.map +1 -1
  237. package/fesm2022/ngwr-switch.mjs +16 -48
  238. package/fesm2022/ngwr-switch.mjs.map +1 -1
  239. package/fesm2022/ngwr-table.mjs +824 -20
  240. package/fesm2022/ngwr-table.mjs.map +1 -1
  241. package/fesm2022/ngwr-tabs.mjs +9 -8
  242. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  243. package/fesm2022/ngwr-textarea.mjs +18 -50
  244. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  245. package/fesm2022/ngwr-theme.mjs +20 -5
  246. package/fesm2022/ngwr-theme.mjs.map +1 -1
  247. package/fesm2022/ngwr-tilt-card.mjs +27 -11
  248. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  249. package/fesm2022/ngwr-timeline.mjs +7 -7
  250. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  251. package/fesm2022/ngwr-toast.mjs +10 -10
  252. package/fesm2022/ngwr-toast.mjs.map +1 -1
  253. package/fesm2022/ngwr-toolbar.mjs +4 -4
  254. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  255. package/fesm2022/ngwr-tree.mjs +280 -84
  256. package/fesm2022/ngwr-tree.mjs.map +1 -1
  257. package/fesm2022/ngwr-typewriter.mjs +10 -5
  258. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  259. package/fesm2022/ngwr-typography.mjs +4 -4
  260. package/fesm2022/ngwr-typography.mjs.map +1 -1
  261. package/fesm2022/ngwr-validators.mjs +1 -1
  262. package/fesm2022/ngwr-validators.mjs.map +1 -1
  263. package/fesm2022/ngwr-version.mjs +1 -1
  264. package/fesm2022/ngwr-version.mjs.map +1 -1
  265. package/fesm2022/ngwr-virtual-scroll.mjs +9 -7
  266. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  267. package/fesm2022/ngwr-waves.mjs +6 -5
  268. package/fesm2022/ngwr-waves.mjs.map +1 -1
  269. package/fesm2022/ngwr-window.mjs +16 -15
  270. package/fesm2022/ngwr-window.mjs.map +1 -1
  271. package/file-upload/styles/_index.scss +11 -11
  272. package/form/styles/_index.scss +4 -4
  273. package/gauge/styles/_index.scss +2 -2
  274. package/glitch-text/styles/_index.scss +1 -1
  275. package/gradient-text/styles/_index.scss +1 -1
  276. package/image-cropper/styles/_index.scss +5 -4
  277. package/input/styles/_index.scss +9 -9
  278. package/input-number/styles/_index.scss +1 -1
  279. package/input-otp/styles/_index.scss +5 -5
  280. package/keyboard/styles/_index.scss +5 -5
  281. package/knob/styles/_index.scss +6 -2
  282. package/layout/styles/_index.scss +12 -12
  283. package/lightbox/styles/_index.scss +10 -8
  284. package/line-chart/styles/_index.scss +5 -5
  285. package/list/styles/_index.scss +3 -3
  286. package/llms-full.txt +31 -5
  287. package/llms.txt +48 -32
  288. package/marquee/styles/_index.scss +1 -1
  289. package/mention/styles/_index.scss +4 -4
  290. package/meter-group/styles/_index.scss +4 -4
  291. package/overlay/styles/_index.scss +8 -0
  292. package/package.json +21 -9
  293. package/page-header/styles/_index.scss +4 -4
  294. package/pagination/styles/_index.scss +3 -3
  295. package/popconfirm/styles/_index.scss +3 -3
  296. package/popover/styles/_index.scss +5 -5
  297. package/progress/styles/_index.scss +1 -1
  298. package/pull-to-refresh/styles/_index.scss +38 -0
  299. package/radio/styles/_index.scss +4 -4
  300. package/rating/styles/_index.scss +1 -1
  301. package/result/styles/_index.scss +3 -3
  302. package/schematics/migrations/v9/index.js +71 -0
  303. package/schematics/migrations.json +5 -0
  304. package/schematics/ng-add/schema.json +1 -1
  305. package/schematics/use/symbol-map.json +13 -0
  306. package/segmented/styles/_index.scss +4 -4
  307. package/select/styles/_index.scss +53 -18
  308. package/shiny-text/styles/_index.scss +4 -4
  309. package/sidebar/styles/_index.scss +12 -12
  310. package/slider/styles/_index.scss +5 -5
  311. package/speed-dial/styles/_index.scss +22 -6
  312. package/splash-cursor/styles/_index.scss +1 -0
  313. package/splitter/styles/_index.scss +7 -4
  314. package/spotlight-card/styles/_index.scss +7 -7
  315. package/star-border/styles/_index.scss +3 -3
  316. package/statistic/styles/_index.scss +51 -4
  317. package/stepper/styles/_index.scss +6 -6
  318. package/styles/_typography.scss +4 -1
  319. package/styles.scss +2 -0
  320. package/switch/styles/_index.scss +4 -4
  321. package/table/styles/_index.scss +447 -17
  322. package/tabs/styles/_index.scss +3 -3
  323. package/textarea/styles/_index.scss +7 -7
  324. package/theme/styles/_colors.scss +27 -3
  325. package/tilt-card/styles/_index.scss +4 -4
  326. package/timeline/styles/_index.scss +7 -6
  327. package/toast/styles/_index.scss +11 -11
  328. package/toolbar/styles/_index.scss +4 -4
  329. package/tree/styles/_index.scss +45 -15
  330. package/types/ngwr-action-sheet.d.ts +75 -0
  331. package/types/ngwr-alert.d.ts +1 -1
  332. package/types/ngwr-anchor.d.ts +1 -1
  333. package/types/ngwr-avatar.d.ts +1 -1
  334. package/types/ngwr-back-top.d.ts +1 -1
  335. package/types/ngwr-badge.d.ts +4 -4
  336. package/types/ngwr-bar-chart.d.ts +1 -1
  337. package/types/ngwr-breadcrumbs.d.ts +1 -1
  338. package/types/ngwr-burger.d.ts +1 -1
  339. package/types/ngwr-button.d.ts +3 -3
  340. package/types/ngwr-calendar-heatmap.d.ts +1 -1
  341. package/types/ngwr-calendar.d.ts +1 -1
  342. package/types/ngwr-card.d.ts +1 -1
  343. package/types/ngwr-carousel.d.ts +1 -1
  344. package/types/ngwr-cascader.d.ts +27 -16
  345. package/types/ngwr-checkbox.d.ts +63 -43
  346. package/types/ngwr-clipboard.d.ts +1 -1
  347. package/types/ngwr-collapse.d.ts +3 -3
  348. package/types/ngwr-color-picker.d.ts +24 -19
  349. package/types/ngwr-command-palette.d.ts +1 -1
  350. package/types/ngwr-compare.d.ts +1 -1
  351. package/types/ngwr-context-menu.d.ts +25 -1
  352. package/types/ngwr-cookie.d.ts +7 -1
  353. package/types/ngwr-counter.d.ts +9 -2
  354. package/types/ngwr-date-picker.d.ts +36 -23
  355. package/types/ngwr-density.d.ts +1 -1
  356. package/types/ngwr-descriptions.d.ts +1 -1
  357. package/types/ngwr-dialog.d.ts +1 -1
  358. package/types/ngwr-directives.d.ts +1 -0
  359. package/types/ngwr-divider.d.ts +2 -2
  360. package/types/ngwr-donut-chart.d.ts +1 -1
  361. package/types/ngwr-drag-drop.d.ts +1 -1
  362. package/types/ngwr-drawer.d.ts +1 -1
  363. package/types/ngwr-dropdown.d.ts +1 -1
  364. package/types/ngwr-empty.d.ts +1 -1
  365. package/types/ngwr-file-upload.d.ts +28 -17
  366. package/types/ngwr-form.d.ts +2 -2
  367. package/types/ngwr-gauge.d.ts +1 -1
  368. package/types/ngwr-hotkey.d.ts +1 -1
  369. package/types/ngwr-i18n.d.ts +1 -1
  370. package/types/ngwr-icon-adapters-lucide.d.ts +5 -3
  371. package/types/ngwr-icon.d.ts +1 -1
  372. package/types/ngwr-image-cropper.d.ts +1 -1
  373. package/types/ngwr-input-number.d.ts +25 -19
  374. package/types/ngwr-input-otp.d.ts +23 -17
  375. package/types/ngwr-input.d.ts +2 -2
  376. package/types/ngwr-keyboard.d.ts +1 -1
  377. package/types/ngwr-knob.d.ts +24 -19
  378. package/types/ngwr-layout.d.ts +1 -1
  379. package/types/ngwr-lightbox.d.ts +1 -1
  380. package/types/ngwr-line-chart.d.ts +1 -1
  381. package/types/ngwr-list.d.ts +1 -1
  382. package/types/ngwr-loading-bar.d.ts +1 -1
  383. package/types/ngwr-marquee.d.ts +1 -1
  384. package/types/ngwr-media.d.ts +1 -1
  385. package/types/ngwr-mention.d.ts +1 -1
  386. package/types/ngwr-meta.d.ts +1 -1
  387. package/types/ngwr-meter-group.d.ts +1 -1
  388. package/types/ngwr-page-header.d.ts +1 -1
  389. package/types/ngwr-pagination.d.ts +1 -1
  390. package/types/ngwr-platform.d.ts +93 -2
  391. package/types/ngwr-popconfirm.d.ts +3 -3
  392. package/types/ngwr-progress.d.ts +2 -2
  393. package/types/ngwr-pull-to-refresh.d.ts +69 -0
  394. package/types/ngwr-qr.d.ts +1 -1
  395. package/types/ngwr-radio.d.ts +25 -22
  396. package/types/ngwr-rating.d.ts +28 -20
  397. package/types/ngwr-result.d.ts +1 -1
  398. package/types/ngwr-rotating-text.d.ts +1 -0
  399. package/types/ngwr-scroll.d.ts +1 -1
  400. package/types/ngwr-segmented.d.ts +1 -1
  401. package/types/ngwr-select.d.ts +93 -26
  402. package/types/ngwr-sidebar.d.ts +1 -1
  403. package/types/ngwr-skeleton.d.ts +2 -2
  404. package/types/ngwr-slider.d.ts +35 -21
  405. package/types/ngwr-sparkline.d.ts +1 -1
  406. package/types/ngwr-speed-dial.d.ts +8 -2
  407. package/types/ngwr-spinner.d.ts +1 -1
  408. package/types/ngwr-splitter.d.ts +1 -1
  409. package/types/ngwr-squircle.d.ts +1 -1
  410. package/types/ngwr-statistic.d.ts +40 -5
  411. package/types/ngwr-stepper.d.ts +2 -2
  412. package/types/ngwr-storage.d.ts +1 -1
  413. package/types/ngwr-switch.d.ts +20 -16
  414. package/types/ngwr-table.d.ts +417 -6
  415. package/types/ngwr-tabs.d.ts +1 -1
  416. package/types/ngwr-textarea.d.ts +21 -18
  417. package/types/ngwr-theme.d.ts +7 -2
  418. package/types/ngwr-tilt-card.d.ts +3 -0
  419. package/types/ngwr-timeline.d.ts +1 -1
  420. package/types/ngwr-toast.d.ts +1 -1
  421. package/types/ngwr-toolbar.d.ts +1 -1
  422. package/types/ngwr-tree.d.ts +100 -19
  423. package/types/ngwr-typography.d.ts +1 -1
  424. package/types/ngwr-validators.d.ts +1 -1
  425. package/types/ngwr-version.d.ts +1 -1
  426. package/types/ngwr-virtual-scroll.d.ts +1 -1
  427. package/types/ngwr-window.d.ts +1 -1
  428. package/typography/styles/_index.scss +11 -11
  429. package/virtual-scroll/styles/_index.scss +1 -1
  430. package/waves/styles/_index.scss +1 -1
  431. package/window/styles/_index.scss +18 -18
@@ -1,7 +1,11 @@
1
1
  import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
2
- import { NgTemplateOutlet, KeyValuePipe } from '@angular/common';
2
+ import { moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
3
+ import { isPlatformBrowser, DOCUMENT, NgTemplateOutlet } from '@angular/common';
3
4
  import * as i0 from '@angular/core';
4
- import { input, inject, TemplateRef, Directive, output, signal, computed, ViewEncapsulation, Component, model, contentChildren } from '@angular/core';
5
+ import { input, inject, TemplateRef, Directive, output, signal, computed, ViewEncapsulation, Component, model, contentChildren, PLATFORM_ID, viewChildren, effect, untracked, viewChild, contentChild } from '@angular/core';
6
+ import * as i1 from '@angular/forms';
7
+ import { FormsModule } from '@angular/forms';
8
+ import { WrCheckbox } from 'ngwr/checkbox';
5
9
  import { WrPagination } from 'ngwr/pagination';
6
10
  import { WrSpinner } from 'ngwr/spinner';
7
11
  import { WrDropdown, WrDropdownMenu } from 'ngwr/dropdown';
@@ -28,16 +32,48 @@ class WrTableCell {
28
32
  /** Column key the template applies to. */
29
33
  columnKey = input.required({ ...(ngDevMode ? { debugName: "columnKey" } : /* istanbul ignore next */ {}), alias: 'wrTableCell' });
30
34
  template = inject(TemplateRef);
31
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTableCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
32
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: WrTableCell, isStandalone: true, selector: "[wrTableCell]", inputs: { columnKey: { classPropertyName: "columnKey", publicName: "wrTableCell", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
35
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
36
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.0", type: WrTableCell, isStandalone: true, selector: "[wrTableCell]", inputs: { columnKey: { classPropertyName: "columnKey", publicName: "wrTableCell", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
33
37
  }
34
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTableCell, decorators: [{
38
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableCell, decorators: [{
35
39
  type: Directive,
36
40
  args: [{
37
41
  selector: '[wrTableCell]',
38
42
  }]
39
43
  }], propDecorators: { columnKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrTableCell", required: true }] }] } });
40
44
 
45
+ /**
46
+ * @license
47
+ *
48
+ * Use of this source code is governed by an MIT-style license that can be
49
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
50
+ */
51
+ /**
52
+ * Provide the detail template revealed when a row is expanded. Adding it turns
53
+ * on the leading expand column; the row object is the template's implicit
54
+ * context.
55
+ *
56
+ * @example
57
+ * ```html
58
+ * <wr-table [columns]="columns" [items]="items" [(expanded)]="expanded" rowKey="id">
59
+ * <ng-template wrTableExpand let-row>
60
+ * <p>{{ row.bio }}</p>
61
+ * </ng-template>
62
+ * </wr-table>
63
+ * ```
64
+ */
65
+ class WrTableExpand {
66
+ template = inject(TemplateRef);
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableExpand, deps: [], target: i0.ɵɵFactoryTarget.Directive });
68
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: WrTableExpand, isStandalone: true, selector: "ng-template[wrTableExpand]", ngImport: i0 });
69
+ }
70
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableExpand, decorators: [{
71
+ type: Directive,
72
+ args: [{
73
+ selector: 'ng-template[wrTableExpand]',
74
+ }]
75
+ }] });
76
+
41
77
  /**
42
78
  * @license
43
79
  *
@@ -90,14 +126,46 @@ class WrTableFilter {
90
126
  emitSelected() {
91
127
  this.selectionChange.emit(this.items().filter(i => i.selected));
92
128
  }
93
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTableFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
94
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: WrTableFilter, isStandalone: true, selector: "wr-table-filter", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<button type=\"button\" class=\"wr-table-filter__trigger\" [wrDropdown]=\"menu\" aria-label=\"Filter column\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\"\n />\n </svg>\n @if (selectedCount() > 0) {\n <span class=\"wr-table-filter__count\">{{ selectedCount() }}</span>\n }\n</button>\n\n<wr-dropdown-menu #menu>\n <div class=\"wr-table-filter__panel\">\n <input\n class=\"wr-table-filter__search\"\n type=\"search\"\n placeholder=\"Search\"\n [value]=\"query()\"\n (input)=\"onSearchInput($event)\"\n />\n\n <div class=\"wr-table-filter__list\">\n @for (item of visible(); track item.value) {\n <button\n type=\"button\"\n class=\"wr-table-filter__item\"\n [class.wr-table-filter__item--selected]=\"item.selected\"\n (click)=\"onToggle(item)\"\n >\n <span class=\"wr-table-filter__check\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </span>\n <span class=\"wr-table-filter__title\">{{ item.title }}</span>\n </button>\n } @empty {\n <div class=\"wr-table-filter__empty\">No matches</div>\n }\n </div>\n\n @if (selectedCount() > 0) {\n <button type=\"button\" class=\"wr-table-filter__reset\" (click)=\"onReset()\">Reset</button>\n }\n </div>\n</wr-dropdown-menu>\n", dependencies: [{ kind: "directive", type: WrDropdown, selector: "[wrDropdown]", inputs: ["wrDropdown", "trigger", "position", "responsive"], outputs: ["opened", "closed"] }, { kind: "component", type: WrDropdownMenu, selector: "wr-dropdown-menu", exportAs: ["wrDropdownMenu"] }], encapsulation: i0.ViewEncapsulation.None });
129
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
130
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrTableFilter, isStandalone: true, selector: "wr-table-filter", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<button type=\"button\" class=\"wr-table-filter__trigger\" [wrDropdown]=\"menu\" aria-label=\"Filter column\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\"\n />\n </svg>\n @if (selectedCount() > 0) {\n <span class=\"wr-table-filter__count\">{{ selectedCount() }}</span>\n }\n</button>\n\n<wr-dropdown-menu #menu>\n <div class=\"wr-table-filter__panel\">\n <input\n class=\"wr-table-filter__search\"\n type=\"search\"\n placeholder=\"Search\"\n [value]=\"query()\"\n (input)=\"onSearchInput($event)\"\n />\n\n <div class=\"wr-table-filter__list\">\n @for (item of visible(); track item.value) {\n <button\n type=\"button\"\n class=\"wr-table-filter__item\"\n [class.wr-table-filter__item--selected]=\"item.selected\"\n (click)=\"onToggle(item)\"\n >\n <span class=\"wr-table-filter__check\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </span>\n <span class=\"wr-table-filter__title\">{{ item.title }}</span>\n </button>\n } @empty {\n <div class=\"wr-table-filter__empty\">No matches</div>\n }\n </div>\n\n @if (selectedCount() > 0) {\n <button type=\"button\" class=\"wr-table-filter__reset\" (click)=\"onReset()\">Reset</button>\n }\n </div>\n</wr-dropdown-menu>\n", dependencies: [{ kind: "directive", type: WrDropdown, selector: "[wrDropdown]", inputs: ["wrDropdown", "trigger", "position", "responsive"], outputs: ["opened", "closed"] }, { kind: "component", type: WrDropdownMenu, selector: "wr-dropdown-menu", exportAs: ["wrDropdownMenu"] }], encapsulation: i0.ViewEncapsulation.None });
95
131
  }
96
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTableFilter, decorators: [{
132
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableFilter, decorators: [{
97
133
  type: Component,
98
134
  args: [{ selector: 'wr-table-filter', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrDropdown, WrDropdownMenu], template: "<button type=\"button\" class=\"wr-table-filter__trigger\" [wrDropdown]=\"menu\" aria-label=\"Filter column\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\"\n />\n </svg>\n @if (selectedCount() > 0) {\n <span class=\"wr-table-filter__count\">{{ selectedCount() }}</span>\n }\n</button>\n\n<wr-dropdown-menu #menu>\n <div class=\"wr-table-filter__panel\">\n <input\n class=\"wr-table-filter__search\"\n type=\"search\"\n placeholder=\"Search\"\n [value]=\"query()\"\n (input)=\"onSearchInput($event)\"\n />\n\n <div class=\"wr-table-filter__list\">\n @for (item of visible(); track item.value) {\n <button\n type=\"button\"\n class=\"wr-table-filter__item\"\n [class.wr-table-filter__item--selected]=\"item.selected\"\n (click)=\"onToggle(item)\"\n >\n <span class=\"wr-table-filter__check\">\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n </span>\n <span class=\"wr-table-filter__title\">{{ item.title }}</span>\n </button>\n } @empty {\n <div class=\"wr-table-filter__empty\">No matches</div>\n }\n </div>\n\n @if (selectedCount() > 0) {\n <button type=\"button\" class=\"wr-table-filter__reset\" (click)=\"onReset()\">Reset</button>\n }\n </div>\n</wr-dropdown-menu>\n" }]
99
135
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
100
136
 
137
+ /**
138
+ * @license
139
+ *
140
+ * Use of this source code is governed by an MIT-style license that can be
141
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
142
+ */
143
+ /**
144
+ * Provide a custom template for a group band's label area. The collapse chevron
145
+ * and the optional group checkbox are still rendered by the table around it, so
146
+ * the template may safely contain its own interactive content. Projecting it
147
+ * does NOT enable grouping — set `[groupBy]` for that.
148
+ *
149
+ * @example
150
+ * ```html
151
+ * <wr-table [columns]="columns" [items]="rows" groupBy="department">
152
+ * <ng-template wrTableGroupHeader let-value let-count="count" let-toggle="toggle">
153
+ * <wr-tag color="primary" (click)="toggle()">{{ value }}</wr-tag>
154
+ * <small>{{ count }} people</small>
155
+ * </ng-template>
156
+ * </wr-table>
157
+ * ```
158
+ */
159
+ class WrTableGroupHeader {
160
+ template = inject(TemplateRef);
161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableGroupHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
162
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.0", type: WrTableGroupHeader, isStandalone: true, selector: "ng-template[wrTableGroupHeader]", ngImport: i0 });
163
+ }
164
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableGroupHeader, decorators: [{
165
+ type: Directive,
166
+ args: [{ selector: 'ng-template[wrTableGroupHeader]' }]
167
+ }] });
168
+
101
169
  /**
102
170
  * @license
103
171
  *
@@ -121,10 +189,10 @@ class WrTableSort {
121
189
  return parts.join(' ');
122
190
  }, /* @ts-ignore */
123
191
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
124
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTableSort, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.4", type: WrTableSort, isStandalone: true, selector: "wr-table-sort", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<svg class="wr-icon__svg wr-table-sort__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 12 7-7 7 7"/><path d="M12 19V5"/></svg>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
192
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableSort, deps: [], target: i0.ɵɵFactoryTarget.Component });
193
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: WrTableSort, isStandalone: true, selector: "wr-table-sort", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: '<svg class="wr-icon__svg wr-table-sort__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 12 7-7 7 7"/><path d="M12 19V5"/></svg>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
126
194
  }
127
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTableSort, decorators: [{
195
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTableSort, decorators: [{
128
196
  type: Component,
129
197
  args: [{
130
198
  selector: 'wr-table-sort',
@@ -140,6 +208,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
140
208
  * Use of this source code is governed by an MIT-style license that can be
141
209
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
142
210
  */
211
+ /** Sentinel value for the single synthetic bucket used when grouping is off. */
212
+ const WR_TABLE_UNGROUPED = Symbol('wr-table-ungrouped');
143
213
  /**
144
214
  * Data table with sortable / filterable headers and custom cell templates.
145
215
  *
@@ -161,7 +231,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
161
231
  * </wr-table>
162
232
  * ```
163
233
  *
164
- * @see https://ngwr.dev/components/table
234
+ * @see https://ngwr.dev/reference/components/table
165
235
  */
166
236
  class WrTable {
167
237
  /** Column definitions, keyed by row property name. */
@@ -178,6 +248,69 @@ class WrTable {
178
248
  * cell shows its column title as a label. @default false
179
249
  */
180
250
  responsive = input(false, { ...(ngDevMode ? { debugName: "responsive" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
251
+ /** Enable drag-to-reorder on the column headers. @default false */
252
+ reorderable = input(false, { ...(ngDevMode ? { debugName: "reorderable" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
253
+ /**
254
+ * Two-way bindable column order — an array of column keys. Reflects and drives
255
+ * the header order: the table falls back to declaration order for any key not
256
+ * listed, and updates this on drag. Bind it to persist a user's arrangement.
257
+ */
258
+ columnOrder = model([], /* @ts-ignore */
259
+ ...(ngDevMode ? [{ debugName: "columnOrder" }] : /* istanbul ignore next */ []));
260
+ /**
261
+ * Row selection with a leading checkbox column — `'multiple'` adds a
262
+ * select-all header; `'single'` keeps one row selected. @default null (off)
263
+ */
264
+ rowSelection = input(null, /* @ts-ignore */
265
+ ...(ngDevMode ? [{ debugName: "rowSelection" }] : /* istanbul ignore next */ []));
266
+ /**
267
+ * How to identify a row for selection — a property name or a function.
268
+ * Unset uses the row object itself (fine for a stable row array).
269
+ */
270
+ rowKey = input(null, /* @ts-ignore */
271
+ ...(ngDevMode ? [{ debugName: "rowKey" }] : /* istanbul ignore next */ []));
272
+ /** Two-way bindable selected row keys. */
273
+ selection = model([], /* @ts-ignore */
274
+ ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
275
+ /** Two-way bindable expanded row keys (needs a `[wrTableExpand]` template). */
276
+ expanded = model([], /* @ts-ignore */
277
+ ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
278
+ /**
279
+ * Group rows under collapsible band headers — a row property name, or a
280
+ * function returning the group value. `null` (default) renders the table
281
+ * exactly as before.
282
+ *
283
+ * Grouping runs AFTER pagination: it buckets the rows on the current page in
284
+ * first-appearance order (it never re-sorts your data — same contract as
285
+ * `[(sort)]`), so a group straddling a page boundary shows a band on both
286
+ * pages, and per-group counts / subtotals are page-scoped. Sort `items` by the
287
+ * same key upstream to keep groups whole, or pair with `pageSize = 0`.
288
+ *
289
+ * Group values are compared by identity (`Map`/`Set`, SameValueZero) — return
290
+ * a primitive, exactly as for `rowKey`. Objects / `Date`s bucket by reference.
291
+ *
292
+ * @default null
293
+ */
294
+ groupBy = input(null, /* @ts-ignore */
295
+ ...(ngDevMode ? [{ debugName: "groupBy" }] : /* istanbul ignore next */ []));
296
+ /**
297
+ * Two-way bindable collapsed group values (the values `groupBy` returns).
298
+ * Keyed by value, so a collapsed group stays collapsed across page changes and
299
+ * re-sorts. Empty (the default) shows every group expanded.
300
+ */
301
+ collapsedGroups = model([], /* @ts-ignore */
302
+ ...(ngDevMode ? [{ debugName: "collapsedGroups" }] : /* istanbul ignore next */ []));
303
+ /**
304
+ * Render an aggregate row under each group using the same `column.summary`
305
+ * definitions as the grand footer, computed over that group's rows on the
306
+ * current page. No-op unless at least one column defines a `summary`. The grand
307
+ * `<tfoot>` is unaffected and still aggregates the whole client dataset — with
308
+ * client-side pagination the two describe different scopes, so pair grouping
309
+ * with `pageSize = 0` when you need them to reconcile. @default false
310
+ */
311
+ groupSummary = input(false, { ...(ngDevMode ? { debugName: "groupSummary" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
312
+ /** Show the page-scoped row-count badge in each group band. @default true */
313
+ showGroupCount = input(true, { ...(ngDevMode ? { debugName: "showGroupCount" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
181
314
  /** Two-way bindable sort array. Order in array = application order. */
182
315
  sort = model([], /* @ts-ignore */
183
316
  ...(ngDevMode ? [{ debugName: "sort" }] : /* istanbul ignore next */ []));
@@ -198,6 +331,43 @@ class WrTable {
198
331
  */
199
332
  totalItems = input(null, /* @ts-ignore */
200
333
  ...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
334
+ /**
335
+ * Window the `<tbody>` so a table of thousands of rows keeps only ~one
336
+ * viewport of `<tr>`s in the DOM. Opt-in and OFF by default — a table
337
+ * without it renders byte-identically to today.
338
+ *
339
+ * Engages ONLY on the flat, fixed-height tier: it silently falls back to the
340
+ * full render whenever a variable-height layout is active — `groupBy`, a
341
+ * `[wrTableExpand]` template, `responsive` card mode, or a visible pager
342
+ * (`pageSize > 0` / `totalItems`). While on, it forces fixed layout for
343
+ * stable column widths and assumes a uniform row height (see `rowHeight`).
344
+ *
345
+ * Intended as static config. Give columns an explicit `width` so the frozen
346
+ * layout is exact (a virtualized table always renders fixed-layout); toggling
347
+ * it off at runtime leaves the frozen widths in place as column minimums.
348
+ * @default false
349
+ */
350
+ virtualScroll = input(false, { ...(ngDevMode ? { debugName: "virtualScroll" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
351
+ /**
352
+ * Uniform body-row height in px used to map scroll offset to row index. `0`
353
+ * (default) measures the first rendered row once — matching the density at
354
+ * that point — and reuses it; pass an explicit value to remove the
355
+ * post-hydration measure and make SSR pixel-exact (recommended if the density
356
+ * can change at runtime). Read only when `virtualScroll` is on. Keep
357
+ * virtualized cells single-line and no taller than this — a taller custom
358
+ * `[wrTableCell]` template drifts the window. @default 0
359
+ */
360
+ rowHeight = input(0, { ...(ngDevMode ? { debugName: "rowHeight" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, coerceNumberProperty(v, 0)) });
361
+ /**
362
+ * Height of the scroll viewport when `virtualScroll` is on — a number (px) or
363
+ * any CSS length (`'70vh'`). Applied as `max-height` on `.wr-table__scroll`
364
+ * (a short table shrinks to fit; a long one caps and scrolls). A numeric px
365
+ * value lets the server prerender the exact first window. @default 480
366
+ */
367
+ viewportHeight = input(480, /* @ts-ignore */
368
+ ...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
369
+ /** Extra rows kept rendered above and below the viewport as scroll headroom. @default 6 */
370
+ overscan = input(6, { ...(ngDevMode ? { debugName: "overscan" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, coerceNumberProperty(v, 6)) });
201
371
  /** Total row count derived for the pager (server-mode wins). */
202
372
  resolvedTotal = computed(() => {
203
373
  const server = this.totalItems();
@@ -234,8 +404,628 @@ class WrTable {
234
404
  return map;
235
405
  }, /* @ts-ignore */
236
406
  ...(ngDevMode ? [{ debugName: "cellMap" }] : /* istanbul ignore next */ []));
237
- /** Keep KeyValuePipe in declaration order (comparator that treats all keys as equal). */
238
- keepOrder = () => 0;
407
+ // --- Column pinning -------------------------------------------------------
408
+ platformId = inject(PLATFORM_ID);
409
+ headerCells = viewChildren('thCell', /* @ts-ignore */
410
+ ...(ngDevMode ? [{ debugName: "headerCells" }] : /* istanbul ignore next */ []));
411
+ /**
412
+ * Columns in render order — declaration order, overridden by `columnOrder`
413
+ * once reordered; new keys append, removed keys drop out. Pin and resize
414
+ * measurement key off this, so it must equal the rendered order.
415
+ */
416
+ displayColumns = computed(() => {
417
+ const cols = this.columns();
418
+ const seen = new Set();
419
+ const result = [];
420
+ for (const key of this.columnOrder()) {
421
+ if (Object.hasOwn(cols, key) && !seen.has(key)) {
422
+ result.push({ key, column: cols[key] });
423
+ seen.add(key);
424
+ }
425
+ }
426
+ for (const key of Object.keys(cols)) {
427
+ if (!seen.has(key)) {
428
+ result.push({ key, column: cols[key] });
429
+ seen.add(key);
430
+ }
431
+ }
432
+ return result;
433
+ }, /* @ts-ignore */
434
+ ...(ngDevMode ? [{ debugName: "displayColumns" }] : /* istanbul ignore next */ []));
435
+ /**
436
+ * Sticky offsets for pinned columns, measured from the header cells so any
437
+ * number of columns can stack per side. Also names the inner-edge column on
438
+ * each side (where the separating shadow sits). Empty until measured in the
439
+ * browser; on the server the pins stay at offset 0, corrected on hydration.
440
+ */
441
+ pins = signal({ left: new Map(), right: new Map(), leftEdge: null, rightEdge: null }, /* @ts-ignore */
442
+ ...(ngDevMode ? [{ debugName: "pins" }] : /* istanbul ignore next */ []));
443
+ constructor() {
444
+ // Re-measure whenever the columns or their rendered widths change. Tables
445
+ // with no pinned column skip the observer entirely.
446
+ effect(onCleanup => {
447
+ const cells = this.headerCells();
448
+ const cols = this.displayColumns();
449
+ if (!cols.some(c => c.column.pin)) {
450
+ this.pins.set({ left: new Map(), right: new Map(), leftEdge: null, rightEdge: null });
451
+ return;
452
+ }
453
+ if (!isPlatformBrowser(this.platformId) || typeof ResizeObserver === 'undefined') {
454
+ this.measurePins(cols, cells);
455
+ return;
456
+ }
457
+ const observer = new ResizeObserver(() => this.measurePins(cols, cells));
458
+ for (const cell of cells)
459
+ observer.observe(cell.nativeElement);
460
+ this.measurePins(cols, cells);
461
+ onCleanup(() => observer.disconnect());
462
+ });
463
+ // Reset resize state when the column KEY SET changes (added/removed/renamed)
464
+ // so a stale frozen width can't collapse a new column under the latched
465
+ // fixed layout. Keyed on sorted keys, not object identity (which churns).
466
+ // Also drops the virtual freeze so activation effect (A), registered after
467
+ // this, re-establishes it from the fresh natural widths.
468
+ effect(() => {
469
+ const keys = Object.keys(this.columns()).sort().join('\n');
470
+ if (keys === this.lastColumnKeys)
471
+ return;
472
+ this.lastColumnKeys = keys;
473
+ this.resizeWidths.set(new Map());
474
+ this.fixedLayout.set(false);
475
+ this.virtualFixed.set(false);
476
+ });
477
+ // (A) Virtual activation: freeze the natural column widths BEFORE fixed
478
+ // layout applies (so there's no jump), then switch to fixed and measure the
479
+ // row height. Tracks columns so a structural change re-freshes the widths —
480
+ // registered AFTER the key-set reset above, so this freeze wins the tie.
481
+ effect(() => {
482
+ const active = this.virtualized();
483
+ this.displayColumns(); // re-run on a structural column change
484
+ if (!active) {
485
+ this.virtualFixed.set(false);
486
+ return;
487
+ }
488
+ if (!isPlatformBrowser(this.platformId))
489
+ return;
490
+ untracked(() => {
491
+ this.freezeColumnWidths(); // captured while still auto-layout = natural widths
492
+ this.virtualFixed.set(true); // now fixed, with those exact widths (no jump)
493
+ if (this.rowHeight() === 0) {
494
+ const row = this.scrollEl()?.nativeElement.querySelector('.wr-table__tr');
495
+ const h = row?.offsetHeight ?? 0;
496
+ if (h > 0)
497
+ this.measuredRowPx.set(h);
498
+ }
499
+ });
500
+ });
501
+ // (B) Scroll + viewport observer — attached ONLY when virtual + browser, so
502
+ // a non-virtual table gets no scroll listener / no per-scroll change detection.
503
+ effect(onCleanup => {
504
+ const el = this.scrollEl()?.nativeElement;
505
+ if (!el || !this.virtualized() || !isPlatformBrowser(this.platformId))
506
+ return;
507
+ let raf = 0;
508
+ const onScroll = () => {
509
+ if (raf)
510
+ return;
511
+ raf = requestAnimationFrame(() => {
512
+ raf = 0;
513
+ this.scrollTop.set(el.scrollTop);
514
+ });
515
+ };
516
+ el.addEventListener('scroll', onScroll, { passive: true });
517
+ this.viewportPx.set(el.clientHeight);
518
+ const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => this.viewportPx.set(el.clientHeight)) : null;
519
+ ro?.observe(el);
520
+ onCleanup(() => {
521
+ el.removeEventListener('scroll', onScroll);
522
+ if (raf)
523
+ cancelAnimationFrame(raf);
524
+ ro?.disconnect();
525
+ });
526
+ });
527
+ }
528
+ measurePins(cols, cells) {
529
+ const left = new Map();
530
+ const right = new Map();
531
+ let leftEdge = null;
532
+ let rightEdge = null;
533
+ let acc = 0;
534
+ for (let i = 0; i < cols.length; i++) {
535
+ if (cols[i].column.pin === 'left') {
536
+ left.set(cols[i].key, acc);
537
+ acc += cells[i]?.nativeElement.offsetWidth ?? 0;
538
+ leftEdge = cols[i].key;
539
+ }
540
+ }
541
+ acc = 0;
542
+ for (let i = cols.length - 1; i >= 0; i--) {
543
+ if (cols[i].column.pin === 'right') {
544
+ right.set(cols[i].key, acc);
545
+ acc += cells[i]?.nativeElement.offsetWidth ?? 0;
546
+ rightEdge = cols[i].key;
547
+ }
548
+ }
549
+ this.pins.set({ left, right, leftEdge, rightEdge });
550
+ }
551
+ /** Sticky `left` offset (px) for a left-pinned column, else `null`. */
552
+ leftPin(key) {
553
+ return this.pins().left.get(key) ?? null;
554
+ }
555
+ /** Sticky `right` offset (px) for a right-pinned column, else `null`. */
556
+ rightPin(key) {
557
+ return this.pins().right.get(key) ?? null;
558
+ }
559
+ /** Whether `key` is the inner-edge pinned column on `side` (carries the shadow). */
560
+ isPinEdge(key, side) {
561
+ return (side === 'left' ? this.pins().leftEdge : this.pins().rightEdge) === key;
562
+ }
563
+ // --- Column resizing ------------------------------------------------------
564
+ resizeWidths = signal(new Map(), /* @ts-ignore */
565
+ ...(ngDevMode ? [{ debugName: "resizeWidths" }] : /* istanbul ignore next */ []));
566
+ resizeKey = null;
567
+ resizeStartX = 0;
568
+ resizeStartWidth = 0;
569
+ lastColumnKeys = '';
570
+ /**
571
+ * Once a column has been dragged, the table switches to fixed layout so the
572
+ * `<col>` widths are honoured exactly (auto layout treats them as minimums).
573
+ */
574
+ fixedLayout = signal(false, /* @ts-ignore */
575
+ ...(ngDevMode ? [{ debugName: "fixedLayout" }] : /* istanbul ignore next */ []));
576
+ /** Current width (px) for a column, or `null` for auto — a live resize wins. */
577
+ colWidth(key) {
578
+ return this.resizeWidths().get(key) ?? this.columns()[key]?.width ?? null;
579
+ }
580
+ /** Freeze every column at its current rendered header width (skips frozen keys). */
581
+ freezeColumnWidths() {
582
+ const cols = this.displayColumns();
583
+ const cells = this.headerCells();
584
+ const frozen = new Map(this.resizeWidths());
585
+ for (let i = 0; i < cols.length; i++) {
586
+ if (!frozen.has(cols[i].key)) {
587
+ const width = cells[i]?.nativeElement.offsetWidth;
588
+ if (width)
589
+ frozen.set(cols[i].key, width);
590
+ }
591
+ }
592
+ this.resizeWidths.set(frozen);
593
+ }
594
+ onResizeStart(event, key, th) {
595
+ event.preventDefault();
596
+ event.stopPropagation();
597
+ // Freeze every column at its current rendered width, then switch to fixed
598
+ // layout — the drag then resizes precisely (both directions) without the
599
+ // content-sized columns jumping.
600
+ if (!this.fixedLayout()) {
601
+ this.freezeColumnWidths();
602
+ this.fixedLayout.set(true);
603
+ }
604
+ this.resizeKey = key;
605
+ this.resizeStartX = event.clientX;
606
+ this.resizeStartWidth = th.offsetWidth;
607
+ event.target.setPointerCapture(event.pointerId);
608
+ }
609
+ onResizeMove(event) {
610
+ if (this.resizeKey === null)
611
+ return;
612
+ const width = Math.max(48, this.resizeStartWidth + (event.clientX - this.resizeStartX));
613
+ this.resizeWidths.set(new Map(this.resizeWidths()).set(this.resizeKey, width));
614
+ }
615
+ onResizeEnd(event) {
616
+ if (this.resizeKey === null)
617
+ return;
618
+ const target = event.target;
619
+ if (target.hasPointerCapture?.(event.pointerId))
620
+ target.releasePointerCapture(event.pointerId);
621
+ this.resizeKey = null;
622
+ }
623
+ // --- Virtual scroll -------------------------------------------------------
624
+ /** md-density fallback row height (px), used before measuring / on the server. */
625
+ static FALLBACK_ROW_PX = 40;
626
+ static FALLBACK_VIEWPORT_PX = 480;
627
+ /** The `.wr-table__scroll` div (always in the template; only read when virtual). */
628
+ scrollEl = viewChild('scroll', /* @ts-ignore */
629
+ ...(ngDevMode ? [{ debugName: "scrollEl" }] : /* istanbul ignore next */ []));
630
+ /** Live vertical scroll offset (px); 0 on the server / before first scroll. */
631
+ scrollTop = signal(0, /* @ts-ignore */
632
+ ...(ngDevMode ? [{ debugName: "scrollTop" }] : /* istanbul ignore next */ []));
633
+ /** Measured viewport clientHeight (px); 0 until the browser observer fires. */
634
+ viewportPx = signal(0, /* @ts-ignore */
635
+ ...(ngDevMode ? [{ debugName: "viewportPx" }] : /* istanbul ignore next */ []));
636
+ /** Measured first-row height (px) when `rowHeight` is auto; 0 until measured. */
637
+ measuredRowPx = signal(0, /* @ts-ignore */
638
+ ...(ngDevMode ? [{ debugName: "measuredRowPx" }] : /* istanbul ignore next */ []));
639
+ /** Fixed layout forced ON by virtualization (distinct from the resize latch). */
640
+ virtualFixed = signal(false, /* @ts-ignore */
641
+ ...(ngDevMode ? [{ debugName: "virtualFixed" }] : /* istanbul ignore next */ []));
642
+ /** `virtualScroll` requested AND the data shape is safe to window. SSR-deterministic. */
643
+ virtualized = computed(() => this.virtualScroll() &&
644
+ this.groupBy() === null && // group bands / subtotals are variable height
645
+ !this.expandable() && // an injected detail <tr> desyncs uniform offsets
646
+ !this.responsive() && // card mode has no uniform row height
647
+ this.pageSize() === 0 && // a visible pager owns chunking — the pager wins
648
+ this.totalItems() === null &&
649
+ !!this.visibleItems(), /* @ts-ignore */
650
+ ...(ngDevMode ? [{ debugName: "virtualized" }] : /* istanbul ignore next */ []));
651
+ /** Effective uniform row height (px). */
652
+ effRowH = computed(() => this.rowHeight() > 0 ? this.rowHeight() : this.measuredRowPx() || WrTable.FALLBACK_ROW_PX, /* @ts-ignore */
653
+ ...(ngDevMode ? [{ debugName: "effRowH" }] : /* istanbul ignore next */ []));
654
+ /** Deterministic viewport px for SSR + first paint (numeric height, else fallback). */
655
+ fallbackViewportPx = computed(() => {
656
+ const h = this.viewportHeight();
657
+ return typeof h === 'number' ? h : WrTable.FALLBACK_VIEWPORT_PX;
658
+ }, /* @ts-ignore */
659
+ ...(ngDevMode ? [{ debugName: "fallbackViewportPx" }] : /* istanbul ignore next */ []));
660
+ /** `viewportHeight` as a CSS length for the inline max-height. */
661
+ resolvedViewportHeight = computed(() => {
662
+ const h = this.viewportHeight();
663
+ return typeof h === 'number' ? `${h}px` : h;
664
+ }, /* @ts-ignore */
665
+ ...(ngDevMode ? [{ debugName: "resolvedViewportHeight" }] : /* istanbul ignore next */ []));
666
+ /** Rendered window [start,end) + spacer pads (px). Pure math, O(1) per scroll frame. */
667
+ virtualWindow = computed(() => {
668
+ const total = this.renderRows().length;
669
+ if (!this.virtualized() || total === 0)
670
+ return { start: 0, end: total, padTop: 0, padBottom: 0 };
671
+ const h = this.effRowH();
672
+ const vp = this.viewportPx() || this.fallbackViewportPx();
673
+ const over = this.overscan();
674
+ const first = Math.floor(this.scrollTop() / h);
675
+ const count = Math.ceil(vp / h);
676
+ const start = Math.max(0, first - over);
677
+ const end = Math.min(total, first + count + over);
678
+ return { start, end, padTop: start * h, padBottom: (total - end) * h };
679
+ }, /* @ts-ignore */
680
+ ...(ngDevMode ? [{ debugName: "virtualWindow" }] : /* istanbul ignore next */ []));
681
+ /** Flat index of the first rendered window row (for `aria-rowindex`). */
682
+ windowStart = computed(() => this.virtualWindow().start, /* @ts-ignore */
683
+ ...(ngDevMode ? [{ debugName: "windowStart" }] : /* istanbul ignore next */ []));
684
+ /** Rows placed in `<tbody>`. SAME array instance as `renderRows()` when off → byte-identical DOM. */
685
+ windowRows = computed(() => {
686
+ if (!this.virtualized())
687
+ return this.renderRows();
688
+ const { start, end } = this.virtualWindow();
689
+ return this.renderRows().slice(start, end);
690
+ }, /* @ts-ignore */
691
+ ...(ngDevMode ? [{ debugName: "windowRows" }] : /* istanbul ignore next */ []));
692
+ /** Fixed layout is on when a resize drag latched it OR virtualization forces it. */
693
+ fixedLayoutActive = computed(() => this.fixedLayout() || this.virtualFixed(), /* @ts-ignore */
694
+ ...(ngDevMode ? [{ debugName: "fixedLayoutActive" }] : /* istanbul ignore next */ []));
695
+ /** Scroll a flat row index to the top of the virtual viewport. No-op on the server / when not virtual. */
696
+ scrollToRow(index, behavior = 'auto') {
697
+ if (!isPlatformBrowser(this.platformId) || !this.virtualized())
698
+ return;
699
+ this.scrollEl()?.nativeElement.scrollTo({ top: Math.max(0, index) * this.effRowH(), behavior });
700
+ }
701
+ onColumnDrop(event) {
702
+ if (event.previousIndex === event.currentIndex)
703
+ return;
704
+ const order = this.displayColumns().map(c => c.key);
705
+ moveItemInArray(order, event.previousIndex, event.currentIndex);
706
+ this.columnOrder.set(order);
707
+ }
708
+ /**
709
+ * Keep pinned columns anchored — a drop can't land on a pinned column's slot,
710
+ * so a scrollable column can't be dragged into the frozen region at either edge.
711
+ */
712
+ sortPredicate = (index) => !this.displayColumns()[index]?.column.pin;
713
+ // --- Row selection --------------------------------------------------------
714
+ rowKeyOf(row) {
715
+ const rk = this.rowKey();
716
+ if (typeof rk === 'function')
717
+ return rk(row);
718
+ if (typeof rk === 'string')
719
+ return row[rk];
720
+ return row;
721
+ }
722
+ /** Keys of the rows on the current page — the select-all scope. */
723
+ pageRowKeys = computed(() => (this.visibleItems() ?? []).map(row => this.rowKeyOf(row)), /* @ts-ignore */
724
+ ...(ngDevMode ? [{ debugName: "pageRowKeys" }] : /* istanbul ignore next */ []));
725
+ isRowSelected(row) {
726
+ return this.selectionSet().has(this.rowKeyOf(row));
727
+ }
728
+ /** Every current-page row selected (drives the header checkbox). */
729
+ allSelected = computed(() => {
730
+ const keys = this.pageRowKeys();
731
+ if (keys.length === 0)
732
+ return false;
733
+ const sel = this.selectionSet();
734
+ return keys.every(key => sel.has(key));
735
+ }, /* @ts-ignore */
736
+ ...(ngDevMode ? [{ debugName: "allSelected" }] : /* istanbul ignore next */ []));
737
+ /** Some but not all selected (drives the header indeterminate). */
738
+ someSelected = computed(() => {
739
+ const sel = this.selectionSet();
740
+ return this.pageRowKeys().some(key => sel.has(key)) && !this.allSelected();
741
+ }, /* @ts-ignore */
742
+ ...(ngDevMode ? [{ debugName: "someSelected" }] : /* istanbul ignore next */ []));
743
+ toggleRow(row, checked) {
744
+ const key = this.rowKeyOf(row);
745
+ if (this.rowSelection() === 'single') {
746
+ this.selection.set(checked ? [key] : []);
747
+ return;
748
+ }
749
+ const sel = this.selection();
750
+ this.selection.set(checked ? [...sel, key] : sel.filter(k => k !== key));
751
+ }
752
+ /** Add (or remove) a set of row keys from the selection in one update. */
753
+ applySelection(keys, checked) {
754
+ const sel = this.selection();
755
+ if (checked) {
756
+ const merged = new Set(sel);
757
+ for (const key of keys)
758
+ merged.add(key);
759
+ this.selection.set([...merged]);
760
+ }
761
+ else {
762
+ const drop = new Set(keys);
763
+ this.selection.set(sel.filter(k => !drop.has(k)));
764
+ }
765
+ }
766
+ toggleAll(checked) {
767
+ this.applySelection(this.pageRowKeys(), checked);
768
+ }
769
+ // --- Row expansion --------------------------------------------------------
770
+ expandTpl = contentChild(WrTableExpand, /* @ts-ignore */
771
+ ...(ngDevMode ? [{ debugName: "expandTpl" }] : /* istanbul ignore next */ []));
772
+ /** Whether the expand column shows (a `[wrTableExpand]` template was projected). */
773
+ expandable = computed(() => !!this.expandTpl(), /* @ts-ignore */
774
+ ...(ngDevMode ? [{ debugName: "expandable" }] : /* istanbul ignore next */ []));
775
+ /** Leading control columns — selection + expand. */
776
+ leadingCols = computed(() => (this.rowSelection() ? 1 : 0) + (this.expandable() ? 1 : 0), /* @ts-ignore */
777
+ ...(ngDevMode ? [{ debugName: "leadingCols" }] : /* istanbul ignore next */ []));
778
+ /** Total rendered columns (data + leading), for detail-row / empty colspans. */
779
+ totalCols = computed(() => this.displayColumns().length + this.leadingCols(), /* @ts-ignore */
780
+ ...(ngDevMode ? [{ debugName: "totalCols" }] : /* istanbul ignore next */ []));
781
+ expandTemplate() {
782
+ return this.expandTpl()?.template;
783
+ }
784
+ isExpanded(row) {
785
+ return this.expanded().includes(this.rowKeyOf(row));
786
+ }
787
+ toggleExpand(row) {
788
+ const key = this.rowKeyOf(row);
789
+ const set = this.expanded();
790
+ this.expanded.set(set.includes(key) ? set.filter(k => k !== key) : [...set, key]);
791
+ }
792
+ expandContext(row) {
793
+ return { $implicit: row, row };
794
+ }
795
+ // --- Summary row ----------------------------------------------------------
796
+ /** Whether any column defines a `summary` (so the footer row shows). */
797
+ hasSummary = computed(() => Object.values(this.columns()).some(col => col.summary !== undefined), /* @ts-ignore */
798
+ ...(ngDevMode ? [{ debugName: "hasSummary" }] : /* istanbul ignore next */ []));
799
+ /** Per-column footer values, computed over `items` (the current page in server mode). */
800
+ summaries = computed(() => {
801
+ const rows = this.items() ?? [];
802
+ const map = new Map();
803
+ for (const [key, col] of Object.entries(this.columns())) {
804
+ if (col.summary !== undefined)
805
+ map.set(key, this.computeSummary(col.summary, rows, key));
806
+ }
807
+ return map;
808
+ }, /* @ts-ignore */
809
+ ...(ngDevMode ? [{ debugName: "summaries" }] : /* istanbul ignore next */ []));
810
+ summaryFor(key) {
811
+ return this.summaries().get(key) ?? '';
812
+ }
813
+ // --- Row grouping ---------------------------------------------------------
814
+ groupTpl = contentChild(WrTableGroupHeader, /* @ts-ignore */
815
+ ...(ngDevMode ? [{ debugName: "groupTpl" }] : /* istanbul ignore next */ []));
816
+ groupTemplate() {
817
+ return this.groupTpl()?.template;
818
+ }
819
+ /**
820
+ * Rows on the current page bucketed by `groupBy`, in first-appearance order.
821
+ * Depends only on `visibleItems()` + `groupBy` (not on collapse / summary), so
822
+ * a collapse toggle never re-buckets. The ungrouped path returns one synthetic
823
+ * bucket holding the same array instance `visibleItems()` returned.
824
+ */
825
+ groupBuckets = computed(() => {
826
+ const rows = this.visibleItems() ?? [];
827
+ const by = this.groupBy();
828
+ if (by === null)
829
+ return [{ value: WR_TABLE_UNGROUPED, rows }];
830
+ const buckets = new Map();
831
+ for (const row of rows) {
832
+ const value = typeof by === 'function' ? by(row) : row[by];
833
+ const bucket = buckets.get(value);
834
+ if (bucket)
835
+ bucket.push(row);
836
+ else
837
+ buckets.set(value, [row]);
838
+ }
839
+ return Array.from(buckets, ([value, groupRows]) => ({ value, rows: groupRows }));
840
+ }, /* @ts-ignore */
841
+ ...(ngDevMode ? [{ debugName: "groupBuckets" }] : /* istanbul ignore next */ []));
842
+ /**
843
+ * The flat `<tbody>` render list. Ungrouped it is exactly today's rows in
844
+ * order (the rendered elements are unchanged; only the `@for` track identity
845
+ * moves to a stable id). Returns `[]` for both no-rows and loading — the
846
+ * template's `@if (visibleItems())` guard keeps the loading case from showing
847
+ * the empty row.
848
+ */
849
+ renderRows = computed(() => {
850
+ const rows = this.visibleItems();
851
+ if (!rows)
852
+ return [];
853
+ const buckets = this.groupBuckets();
854
+ if (this.groupBy() === null) {
855
+ return buckets[0].rows.map((row, i) => ({ kind: 'row', id: `r${i}`, row }));
856
+ }
857
+ const collapsed = new Set(this.collapsedGroups());
858
+ const summaryCols = this.groupSummary() && this.hasSummary()
859
+ ? Object.entries(this.columns()).filter(([, c]) => c.summary !== undefined)
860
+ : [];
861
+ const out = [];
862
+ buckets.forEach((bucket, gi) => {
863
+ const isCollapsed = collapsed.has(bucket.value);
864
+ const label = this.groupLabelOf(bucket.value);
865
+ const group = {
866
+ $implicit: bucket.value,
867
+ value: bucket.value,
868
+ label,
869
+ rows: bucket.rows,
870
+ count: bucket.rows.length,
871
+ collapsed: isCollapsed,
872
+ index: gi,
873
+ toggle: () => this.toggleGroupCollapse(bucket.value),
874
+ };
875
+ out.push({ kind: 'group', id: `g${gi}`, group });
876
+ if (isCollapsed)
877
+ return;
878
+ bucket.rows.forEach((row, ri) => out.push({ kind: 'row', id: `g${gi}r${ri}`, row }));
879
+ if (summaryCols.length) {
880
+ const summaries = new Map();
881
+ for (const [key, col] of summaryCols)
882
+ summaries.set(key, this.computeSummary(col.summary, bucket.rows, key));
883
+ out.push({ kind: 'group-foot', id: `g${gi}f`, summaries });
884
+ }
885
+ });
886
+ return out;
887
+ }, /* @ts-ignore */
888
+ ...(ngDevMode ? [{ debugName: "renderRows" }] : /* istanbul ignore next */ []));
889
+ /** Default band label — the primitive as text, `'—'` for empty, JSON for objects. */
890
+ groupLabelOf(value) {
891
+ if (value == null || value === '')
892
+ return '—';
893
+ if (typeof value === 'string')
894
+ return value;
895
+ if (typeof value === 'number' || typeof value === 'bigint' || typeof value === 'boolean')
896
+ return String(value);
897
+ // Objects / symbols / functions aren't the documented contract (groupBy
898
+ // should return a primitive, like rowKey); format gracefully anyway.
899
+ try {
900
+ return JSON.stringify(value) ?? '—';
901
+ }
902
+ catch {
903
+ return '—';
904
+ }
905
+ }
906
+ toggleGroupCollapse(value) {
907
+ const set = this.collapsedGroups();
908
+ this.collapsedGroups.set(set.includes(value) ? set.filter(v => v !== value) : [...set, value]);
909
+ }
910
+ /** Collapse every group on the current page. No-op when `groupBy` is unset. */
911
+ collapseAllGroups() {
912
+ if (this.groupBy() === null)
913
+ return;
914
+ this.collapsedGroups.set(this.groupBuckets().map(b => b.value));
915
+ }
916
+ /** Expand every group. */
917
+ expandAllGroups() {
918
+ this.collapsedGroups.set([]);
919
+ }
920
+ // --- Group selection (memoized Set; reuses the row-selection primitive) ----
921
+ /** Memoized selection as a Set — O(1) membership for row + group + select-all checks. */
922
+ selectionSet = computed(() => new Set(this.selection()), /* @ts-ignore */
923
+ ...(ngDevMode ? [{ debugName: "selectionSet" }] : /* istanbul ignore next */ []));
924
+ groupChecked(rows) {
925
+ if (rows.length === 0)
926
+ return false;
927
+ const sel = this.selectionSet();
928
+ return rows.every(r => sel.has(this.rowKeyOf(r)));
929
+ }
930
+ groupIndeterminate(rows) {
931
+ const sel = this.selectionSet();
932
+ return rows.some(r => sel.has(this.rowKeyOf(r))) && !this.groupChecked(rows);
933
+ }
934
+ toggleGroupSelection(rows, checked) {
935
+ this.applySelection(rows.map(r => this.rowKeyOf(r)), checked);
936
+ }
937
+ // --- CSV export -----------------------------------------------------------
938
+ doc = inject(DOCUMENT);
939
+ /**
940
+ * Build the table as an RFC-4180 CSV string — a header row from the column
941
+ * titles, then one row per item in the current column order. Values are taken
942
+ * from the row data, not from custom `[wrTableCell]` templates.
943
+ *
944
+ * Covers the current `items`, so in server-side mode (`totalItems` set) it
945
+ * exports the current page, while client-side pagination exports every page.
946
+ *
947
+ * @example
948
+ * ```html
949
+ * <wr-table #table [columns]="columns" [items]="rows" />
950
+ * <wr-btn (click)="table.exportCsv({ filename: 'users.csv' })">Export</wr-btn>
951
+ * ```
952
+ */
953
+ toCsv(options = {}) {
954
+ const delimiter = options.delimiter ?? ',';
955
+ const escapeFormulas = options.escapeFormulas ?? true;
956
+ const cols = this.displayColumns();
957
+ const rows = options.selectedOnly ? this.selectedRows() : (this.items() ?? []);
958
+ const text = (value) => {
959
+ if (value == null)
960
+ return '';
961
+ if (typeof value === 'string')
962
+ return value;
963
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint')
964
+ return String(value);
965
+ if (value instanceof Date)
966
+ return Number.isNaN(value.getTime()) ? '' : value.toISOString();
967
+ try {
968
+ return JSON.stringify(value) ?? '';
969
+ }
970
+ catch {
971
+ // Circular structures and nested bigints throw — never fail the export over one cell.
972
+ return '';
973
+ }
974
+ };
975
+ const cell = (value) => {
976
+ let s = text(value);
977
+ // Spreadsheets evaluate cells starting with these, so neutralize them into text.
978
+ if (escapeFormulas && typeof value === 'string' && /^[=+\-@\t\r]/.test(s))
979
+ s = `'${s}`;
980
+ return s.includes(delimiter) || /["\r\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
981
+ };
982
+ const lines = [cols.map(col => cell(col.column.title)).join(delimiter)];
983
+ for (const row of rows)
984
+ lines.push(cols.map(col => cell(row[col.key])).join(delimiter));
985
+ return lines.join('\r\n');
986
+ }
987
+ /** Download the table as a CSV file. No-op on the server. */
988
+ exportCsv(options = {}) {
989
+ if (!isPlatformBrowser(this.platformId))
990
+ return;
991
+ // Lead with a BOM so Excel reads the file as UTF-8.
992
+ const blob = new Blob([`\uFEFF${this.toCsv(options)}`], { type: 'text/csv;charset=utf-8;' });
993
+ const url = URL.createObjectURL(blob);
994
+ const link = this.doc.createElement('a');
995
+ link.href = url;
996
+ link.download = options.filename ?? 'table.csv';
997
+ link.click();
998
+ setTimeout(() => URL.revokeObjectURL(url));
999
+ }
1000
+ selectedRows() {
1001
+ const keys = new Set(this.selection());
1002
+ return (this.items() ?? []).filter(row => keys.has(this.rowKeyOf(row)));
1003
+ }
1004
+ computeSummary(kind, rows, key) {
1005
+ if (typeof kind === 'function')
1006
+ return kind(rows);
1007
+ // Drop empty/nullish cells first — `Number('')`/`Number(null)` are 0 and
1008
+ // would otherwise skew the aggregate.
1009
+ const values = rows.map(row => row[key]).filter(v => v != null && v !== '');
1010
+ if (kind === 'count')
1011
+ return values.length;
1012
+ const nums = values.map(Number).filter(Number.isFinite);
1013
+ if (nums.length === 0)
1014
+ return '';
1015
+ const sum = nums.reduce((a, b) => a + b, 0);
1016
+ switch (kind) {
1017
+ case 'sum':
1018
+ return sum;
1019
+ case 'avg':
1020
+ return Math.round((sum / nums.length) * 100) / 100;
1021
+ case 'min':
1022
+ return Math.min(...nums);
1023
+ case 'max':
1024
+ return Math.max(...nums);
1025
+ default:
1026
+ return '';
1027
+ }
1028
+ }
239
1029
  directionFor(key) {
240
1030
  return this.sort().find(s => s.key === key)?.direction ?? null;
241
1031
  }
@@ -259,17 +1049,31 @@ class WrTable {
259
1049
  templateFor(key) {
260
1050
  return this.cellMap().get(String(key));
261
1051
  }
262
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
263
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: WrTable, isStandalone: true, selector: "wr-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, totalItems: { classPropertyName: "totalItems", publicName: "totalItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sort: "sortChange", filterChange: "filterChange", page: "pageChange" }, host: { properties: { "class.wr-table--responsive": "responsive()" }, classAttribute: "wr-table" }, queries: [{ propertyName: "cellTemplates", predicate: WrTableCell, isSignal: true }], ngImport: i0, template: "@if (loading()) {\n <div class=\"wr-table__loading\">\n <wr-spinner size=\"lg\" />\n </div>\n}\n\n<div class=\"wr-table__scroll\">\n <table class=\"wr-table__table\">\n <thead>\n <tr>\n @for (entry of columns() | keyvalue: keepOrder; track entry.key) {\n <th class=\"wr-table__th\">\n <div class=\"wr-table__th-inner\">\n <span class=\"wr-table__title\">{{ entry.value.title }}</span>\n\n @if (entry.value.sortable) {\n <button\n type=\"button\"\n class=\"wr-table__sort-btn\"\n aria-label=\"Sort column\"\n (click)=\"cycleSort(entry.key)\"\n >\n <wr-table-sort [direction]=\"directionFor(entry.key)\" />\n </button>\n }\n\n @if (entry.value.filterItems; as filterItems) {\n @if (filterItems.length) {\n <wr-table-filter [items]=\"filterItems\" (selectionChange)=\"onFilter(entry.key, $event)\" />\n }\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @if (visibleItems(); as rows) {\n @for (row of rows; track $index) {\n <tr class=\"wr-table__tr\">\n @for (entry of columns() | keyvalue: keepOrder; track entry.key) {\n <td class=\"wr-table__td\" [attr.data-label]=\"entry.value.title\">\n @if (templateFor(entry.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"cellContext(row, entry.key, entry.value)\"\n />\n } @else {\n {{ getValue(row, entry.key) }}\n }\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td class=\"wr-table__empty\" [attr.colspan]=\"(columns() | keyvalue).length\">No data</td>\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPager()) {\n <div class=\"wr-table__pager\">\n <wr-pagination [(currentPage)]=\"page\" [pageSize]=\"pageSize()\" [total]=\"resolvedTotal()\" />\n </div>\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: WrPagination, selector: "wr-pagination", inputs: ["currentPage", "pageSize", "total", "pageSizeOptions", "showSizeChanger", "showTotal", "align", "size", "shape", "disabled", "responsive", "ofLabel", "prevLabel", "nextLabel", "itemsPerPageLabel"], outputs: ["currentPageChange", "pageSizeChange"] }, { kind: "component", type: WrSpinner, selector: "wr-spinner", inputs: ["size"] }, { kind: "component", type: WrTableSort, selector: "wr-table-sort", inputs: ["direction"] }, { kind: "component", type: WrTableFilter, selector: "wr-table-filter", inputs: ["items"], outputs: ["selectionChange"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], encapsulation: i0.ViewEncapsulation.None });
1052
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
1053
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrTable, isStandalone: true, selector: "wr-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, reorderable: { classPropertyName: "reorderable", publicName: "reorderable", isSignal: true, isRequired: false, transformFunction: null }, columnOrder: { classPropertyName: "columnOrder", publicName: "columnOrder", isSignal: true, isRequired: false, transformFunction: null }, rowSelection: { classPropertyName: "rowSelection", publicName: "rowSelection", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null }, collapsedGroups: { classPropertyName: "collapsedGroups", publicName: "collapsedGroups", isSignal: true, isRequired: false, transformFunction: null }, groupSummary: { classPropertyName: "groupSummary", publicName: "groupSummary", isSignal: true, isRequired: false, transformFunction: null }, showGroupCount: { classPropertyName: "showGroupCount", publicName: "showGroupCount", isSignal: true, isRequired: false, transformFunction: null }, sort: { classPropertyName: "sort", publicName: "sort", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, totalItems: { classPropertyName: "totalItems", publicName: "totalItems", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, viewportHeight: { classPropertyName: "viewportHeight", publicName: "viewportHeight", isSignal: true, isRequired: false, transformFunction: null }, overscan: { classPropertyName: "overscan", publicName: "overscan", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { columnOrder: "columnOrderChange", selection: "selectionChange", expanded: "expandedChange", collapsedGroups: "collapsedGroupsChange", sort: "sortChange", filterChange: "filterChange", page: "pageChange" }, host: { properties: { "class.wr-table--responsive": "responsive()", "class.wr-table--virtual": "virtualized()" }, classAttribute: "wr-table" }, queries: [{ propertyName: "cellTemplates", predicate: WrTableCell, isSignal: true }, { propertyName: "expandTpl", first: true, predicate: WrTableExpand, descendants: true, isSignal: true }, { propertyName: "groupTpl", first: true, predicate: WrTableGroupHeader, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "headerCells", predicate: ["thCell"], descendants: true, isSignal: true }, { propertyName: "scrollEl", first: true, predicate: ["scroll"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (loading()) {\n <div class=\"wr-table__loading\">\n <wr-spinner size=\"lg\" />\n </div>\n}\n\n<div\n class=\"wr-table__scroll\"\n #scroll\n [style.max-height]=\"virtualized() ? resolvedViewportHeight() : null\"\n [attr.tabindex]=\"virtualized() ? 0 : null\"\n>\n <table\n class=\"wr-table__table\"\n [class.wr-table__table--fixed]=\"fixedLayoutActive()\"\n [style.--wr-table-row-h.px]=\"virtualized() ? effRowH() : null\"\n [attr.aria-rowcount]=\"virtualized() ? renderRows().length + 1 + (hasSummary() && items()?.length ? 1 : 0) : null\"\n >\n <colgroup>\n @if (rowSelection()) {\n <col class=\"wr-table__col--lead\" />\n }\n @if (expandable()) {\n <col class=\"wr-table__col--lead\" />\n }\n @for (col of displayColumns(); track col.key) {\n <col [style.width.px]=\"colWidth(col.key)\" />\n }\n </colgroup>\n <thead>\n <tr\n cdkDropList\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListSortPredicate]=\"sortPredicate\"\n (cdkDropListDropped)=\"onColumnDrop($event)\"\n >\n @if (rowSelection()) {\n <th class=\"wr-table__th wr-table__th--select\">\n @if (rowSelection() === 'multiple') {\n <wr-checkbox\n size=\"sm\"\n [ngModel]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (ngModelChange)=\"toggleAll($event)\"\n aria-label=\"Select all rows\"\n />\n }\n </th>\n }\n @if (expandable()) {\n <th class=\"wr-table__th wr-table__th--expand\"></th>\n }\n @for (col of displayColumns(); track col.key) {\n <th\n #thCell\n cdkDrag\n [cdkDragDisabled]=\"!reorderable() || !!col.column.pin\"\n class=\"wr-table__th\"\n [class.wr-table__th--draggable]=\"reorderable() && !col.column.pin\"\n [class.wr-table__th--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__th--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__th--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__th--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n >\n <div class=\"wr-table__th-inner\">\n <span class=\"wr-table__title\">{{ col.column.title }}</span>\n\n @if (col.column.sortable) {\n <button type=\"button\" class=\"wr-table__sort-btn\" aria-label=\"Sort column\" (click)=\"cycleSort(col.key)\">\n <wr-table-sort [direction]=\"directionFor(col.key)\" />\n </button>\n }\n\n @if (col.column.filterItems; as filterItems) {\n @if (filterItems.length) {\n <wr-table-filter [items]=\"filterItems\" (selectionChange)=\"onFilter(col.key, $event)\" />\n }\n }\n </div>\n\n @if (col.column.resizable) {\n <span\n class=\"wr-table__resize-handle\"\n aria-hidden=\"true\"\n (pointerdown)=\"onResizeStart($event, col.key, thCell)\"\n (pointermove)=\"onResizeMove($event)\"\n (pointerup)=\"onResizeEnd($event)\"\n (pointercancel)=\"onResizeEnd($event)\"\n (mousedown)=\"$event.stopPropagation()\"\n (touchstart)=\"$event.stopPropagation()\"\n ></span>\n }\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @if (visibleItems()) {\n @if (virtualized() && virtualWindow().padTop > 0) {\n <tr class=\"wr-table__spacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"totalCols()\" [style.height.px]=\"virtualWindow().padTop\"></td>\n </tr>\n }\n @for (entry of windowRows(); track entry.id; let i = $index) {\n @if (entry.kind === 'group') {\n <tr class=\"wr-table__group-row\" [class.wr-table__group-row--collapsed]=\"entry.group.collapsed\">\n <td class=\"wr-table__group-cell\" [attr.colspan]=\"totalCols()\">\n <!-- The cell spans the full table width; this inner box is what sticks. -->\n <div class=\"wr-table__group-inner\">\n @if (rowSelection() === 'multiple') {\n <wr-checkbox\n class=\"wr-table__group-select\"\n size=\"sm\"\n [ngModel]=\"groupChecked(entry.group.rows)\"\n [indeterminate]=\"groupIndeterminate(entry.group.rows)\"\n (ngModelChange)=\"toggleGroupSelection(entry.group.rows, $event)\"\n aria-label=\"Select group\"\n />\n }\n @if (groupTemplate(); as tpl) {\n <button\n type=\"button\"\n class=\"wr-table__group-toggle wr-table__group-toggle--icon\"\n [attr.aria-expanded]=\"!entry.group.collapsed\"\n aria-label=\"Toggle group\"\n (click)=\"toggleGroupCollapse(entry.group.value)\"\n >\n <svg\n class=\"wr-icon__svg wr-table__group-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"entry.group\" />\n } @else {\n <button\n type=\"button\"\n class=\"wr-table__group-toggle\"\n [attr.aria-expanded]=\"!entry.group.collapsed\"\n (click)=\"toggleGroupCollapse(entry.group.value)\"\n >\n <svg\n class=\"wr-icon__svg wr-table__group-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n <span class=\"wr-table__group-label\">{{ entry.group.label }}</span>\n @if (showGroupCount()) {\n <span class=\"wr-table__group-count\">{{ entry.group.count }}</span>\n }\n </button>\n }\n </div>\n </td>\n </tr>\n } @else if (entry.kind === 'group-foot') {\n <tr class=\"wr-table__group-foot-row\">\n @if (rowSelection()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @if (expandable()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @for (col of displayColumns(); track col.key) {\n <td\n class=\"wr-table__foot-cell\"\n [class.wr-table__td--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__td--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__td--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__td--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n >\n {{ entry.summaries.get(col.key) ?? '' }}\n </td>\n }\n </tr>\n } @else {\n <tr\n class=\"wr-table__tr\"\n [class.wr-table__tr--selected]=\"rowSelection() && isRowSelected(entry.row)\"\n [attr.aria-rowindex]=\"virtualized() ? windowStart() + i + 2 : null\"\n >\n @if (rowSelection()) {\n <td class=\"wr-table__td wr-table__td--select\">\n <wr-checkbox\n size=\"sm\"\n [ngModel]=\"isRowSelected(entry.row)\"\n (ngModelChange)=\"toggleRow(entry.row, $event)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @if (expandable()) {\n <td class=\"wr-table__td wr-table__td--expand\">\n <button\n type=\"button\"\n class=\"wr-table__expand-btn\"\n [class.wr-table__expand-btn--open]=\"isExpanded(entry.row)\"\n [attr.aria-expanded]=\"isExpanded(entry.row)\"\n aria-label=\"Toggle row details\"\n (click)=\"toggleExpand(entry.row)\"\n >\n <svg\n class=\"wr-icon__svg wr-table__expand-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n </td>\n }\n @for (col of displayColumns(); track col.key) {\n <td\n class=\"wr-table__td\"\n [class.wr-table__td--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__td--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__td--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__td--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n [attr.data-label]=\"col.column.title\"\n >\n @if (templateFor(col.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"cellContext(entry.row, col.key, col.column)\"\n />\n } @else {\n {{ getValue(entry.row, col.key) }}\n }\n </td>\n }\n </tr>\n @if (expandable() && isExpanded(entry.row)) {\n <tr class=\"wr-table__detail-row\">\n <td class=\"wr-table__detail\" [attr.colspan]=\"totalCols()\">\n <ng-container\n [ngTemplateOutlet]=\"expandTemplate() ?? null\"\n [ngTemplateOutletContext]=\"expandContext(entry.row)\"\n />\n </td>\n </tr>\n }\n }\n } @empty {\n <tr>\n <td class=\"wr-table__empty\" [attr.colspan]=\"totalCols()\">No data</td>\n </tr>\n }\n @if (virtualized() && virtualWindow().padBottom > 0) {\n <tr class=\"wr-table__spacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"totalCols()\" [style.height.px]=\"virtualWindow().padBottom\"></td>\n </tr>\n }\n }\n </tbody>\n\n @if (hasSummary() && items()?.length) {\n <tfoot>\n <tr class=\"wr-table__foot-row\">\n @if (rowSelection()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @if (expandable()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @for (col of displayColumns(); track col.key) {\n <td\n class=\"wr-table__foot-cell\"\n [class.wr-table__td--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__td--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__td--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__td--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n >\n {{ summaryFor(col.key) }}\n </td>\n }\n </tr>\n </tfoot>\n }\n </table>\n</div>\n\n@if (showPager()) {\n <div class=\"wr-table__pager\">\n <wr-pagination [(currentPage)]=\"page\" [pageSize]=\"pageSize()\" [total]=\"resolvedTotal()\" />\n </div>\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: WrCheckbox, selector: "wr-checkbox", inputs: ["id", "checkboxValue", "checked", "disabled", "size", "icon", "indeterminate"], outputs: ["checkedChange", "touch"] }, { kind: "component", type: WrPagination, selector: "wr-pagination", inputs: ["currentPage", "pageSize", "total", "pageSizeOptions", "showSizeChanger", "showTotal", "align", "size", "shape", "disabled", "responsive", "ofLabel", "prevLabel", "nextLabel", "itemsPerPageLabel"], outputs: ["currentPageChange", "pageSizeChange"] }, { kind: "component", type: WrSpinner, selector: "wr-spinner", inputs: ["size"] }, { kind: "component", type: WrTableSort, selector: "wr-table-sort", inputs: ["direction"] }, { kind: "component", type: WrTableFilter, selector: "wr-table-filter", inputs: ["items"], outputs: ["selectionChange"] }], encapsulation: i0.ViewEncapsulation.None });
264
1054
  }
265
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: WrTable, decorators: [{
1055
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrTable, decorators: [{
266
1056
  type: Component,
267
- args: [{ selector: 'wr-table', encapsulation: ViewEncapsulation.None, host: { class: 'wr-table', '[class.wr-table--responsive]': 'responsive()' }, imports: [NgTemplateOutlet, KeyValuePipe, WrPagination, WrSpinner, WrTableSort, WrTableFilter], template: "@if (loading()) {\n <div class=\"wr-table__loading\">\n <wr-spinner size=\"lg\" />\n </div>\n}\n\n<div class=\"wr-table__scroll\">\n <table class=\"wr-table__table\">\n <thead>\n <tr>\n @for (entry of columns() | keyvalue: keepOrder; track entry.key) {\n <th class=\"wr-table__th\">\n <div class=\"wr-table__th-inner\">\n <span class=\"wr-table__title\">{{ entry.value.title }}</span>\n\n @if (entry.value.sortable) {\n <button\n type=\"button\"\n class=\"wr-table__sort-btn\"\n aria-label=\"Sort column\"\n (click)=\"cycleSort(entry.key)\"\n >\n <wr-table-sort [direction]=\"directionFor(entry.key)\" />\n </button>\n }\n\n @if (entry.value.filterItems; as filterItems) {\n @if (filterItems.length) {\n <wr-table-filter [items]=\"filterItems\" (selectionChange)=\"onFilter(entry.key, $event)\" />\n }\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @if (visibleItems(); as rows) {\n @for (row of rows; track $index) {\n <tr class=\"wr-table__tr\">\n @for (entry of columns() | keyvalue: keepOrder; track entry.key) {\n <td class=\"wr-table__td\" [attr.data-label]=\"entry.value.title\">\n @if (templateFor(entry.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"cellContext(row, entry.key, entry.value)\"\n />\n } @else {\n {{ getValue(row, entry.key) }}\n }\n </td>\n }\n </tr>\n } @empty {\n <tr>\n <td class=\"wr-table__empty\" [attr.colspan]=\"(columns() | keyvalue).length\">No data</td>\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPager()) {\n <div class=\"wr-table__pager\">\n <wr-pagination [(currentPage)]=\"page\" [pageSize]=\"pageSize()\" [total]=\"resolvedTotal()\" />\n </div>\n}\n" }]
268
- }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], sort: [{ type: i0.Input, args: [{ isSignal: true, alias: "sort", required: false }] }, { type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], totalItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalItems", required: false }] }], cellTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => WrTableCell), { isSignal: true }] }] } });
1057
+ args: [{ selector: 'wr-table', encapsulation: ViewEncapsulation.None, host: {
1058
+ class: 'wr-table',
1059
+ '[class.wr-table--responsive]': 'responsive()',
1060
+ '[class.wr-table--virtual]': 'virtualized()',
1061
+ }, imports: [
1062
+ NgTemplateOutlet,
1063
+ FormsModule,
1064
+ CdkDropList,
1065
+ CdkDrag,
1066
+ WrCheckbox,
1067
+ WrPagination,
1068
+ WrSpinner,
1069
+ WrTableSort,
1070
+ WrTableFilter,
1071
+ ], template: "@if (loading()) {\n <div class=\"wr-table__loading\">\n <wr-spinner size=\"lg\" />\n </div>\n}\n\n<div\n class=\"wr-table__scroll\"\n #scroll\n [style.max-height]=\"virtualized() ? resolvedViewportHeight() : null\"\n [attr.tabindex]=\"virtualized() ? 0 : null\"\n>\n <table\n class=\"wr-table__table\"\n [class.wr-table__table--fixed]=\"fixedLayoutActive()\"\n [style.--wr-table-row-h.px]=\"virtualized() ? effRowH() : null\"\n [attr.aria-rowcount]=\"virtualized() ? renderRows().length + 1 + (hasSummary() && items()?.length ? 1 : 0) : null\"\n >\n <colgroup>\n @if (rowSelection()) {\n <col class=\"wr-table__col--lead\" />\n }\n @if (expandable()) {\n <col class=\"wr-table__col--lead\" />\n }\n @for (col of displayColumns(); track col.key) {\n <col [style.width.px]=\"colWidth(col.key)\" />\n }\n </colgroup>\n <thead>\n <tr\n cdkDropList\n cdkDropListOrientation=\"horizontal\"\n [cdkDropListSortPredicate]=\"sortPredicate\"\n (cdkDropListDropped)=\"onColumnDrop($event)\"\n >\n @if (rowSelection()) {\n <th class=\"wr-table__th wr-table__th--select\">\n @if (rowSelection() === 'multiple') {\n <wr-checkbox\n size=\"sm\"\n [ngModel]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (ngModelChange)=\"toggleAll($event)\"\n aria-label=\"Select all rows\"\n />\n }\n </th>\n }\n @if (expandable()) {\n <th class=\"wr-table__th wr-table__th--expand\"></th>\n }\n @for (col of displayColumns(); track col.key) {\n <th\n #thCell\n cdkDrag\n [cdkDragDisabled]=\"!reorderable() || !!col.column.pin\"\n class=\"wr-table__th\"\n [class.wr-table__th--draggable]=\"reorderable() && !col.column.pin\"\n [class.wr-table__th--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__th--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__th--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__th--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n >\n <div class=\"wr-table__th-inner\">\n <span class=\"wr-table__title\">{{ col.column.title }}</span>\n\n @if (col.column.sortable) {\n <button type=\"button\" class=\"wr-table__sort-btn\" aria-label=\"Sort column\" (click)=\"cycleSort(col.key)\">\n <wr-table-sort [direction]=\"directionFor(col.key)\" />\n </button>\n }\n\n @if (col.column.filterItems; as filterItems) {\n @if (filterItems.length) {\n <wr-table-filter [items]=\"filterItems\" (selectionChange)=\"onFilter(col.key, $event)\" />\n }\n }\n </div>\n\n @if (col.column.resizable) {\n <span\n class=\"wr-table__resize-handle\"\n aria-hidden=\"true\"\n (pointerdown)=\"onResizeStart($event, col.key, thCell)\"\n (pointermove)=\"onResizeMove($event)\"\n (pointerup)=\"onResizeEnd($event)\"\n (pointercancel)=\"onResizeEnd($event)\"\n (mousedown)=\"$event.stopPropagation()\"\n (touchstart)=\"$event.stopPropagation()\"\n ></span>\n }\n </th>\n }\n </tr>\n </thead>\n\n <tbody>\n @if (visibleItems()) {\n @if (virtualized() && virtualWindow().padTop > 0) {\n <tr class=\"wr-table__spacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"totalCols()\" [style.height.px]=\"virtualWindow().padTop\"></td>\n </tr>\n }\n @for (entry of windowRows(); track entry.id; let i = $index) {\n @if (entry.kind === 'group') {\n <tr class=\"wr-table__group-row\" [class.wr-table__group-row--collapsed]=\"entry.group.collapsed\">\n <td class=\"wr-table__group-cell\" [attr.colspan]=\"totalCols()\">\n <!-- The cell spans the full table width; this inner box is what sticks. -->\n <div class=\"wr-table__group-inner\">\n @if (rowSelection() === 'multiple') {\n <wr-checkbox\n class=\"wr-table__group-select\"\n size=\"sm\"\n [ngModel]=\"groupChecked(entry.group.rows)\"\n [indeterminate]=\"groupIndeterminate(entry.group.rows)\"\n (ngModelChange)=\"toggleGroupSelection(entry.group.rows, $event)\"\n aria-label=\"Select group\"\n />\n }\n @if (groupTemplate(); as tpl) {\n <button\n type=\"button\"\n class=\"wr-table__group-toggle wr-table__group-toggle--icon\"\n [attr.aria-expanded]=\"!entry.group.collapsed\"\n aria-label=\"Toggle group\"\n (click)=\"toggleGroupCollapse(entry.group.value)\"\n >\n <svg\n class=\"wr-icon__svg wr-table__group-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n <ng-container [ngTemplateOutlet]=\"tpl\" [ngTemplateOutletContext]=\"entry.group\" />\n } @else {\n <button\n type=\"button\"\n class=\"wr-table__group-toggle\"\n [attr.aria-expanded]=\"!entry.group.collapsed\"\n (click)=\"toggleGroupCollapse(entry.group.value)\"\n >\n <svg\n class=\"wr-icon__svg wr-table__group-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n <span class=\"wr-table__group-label\">{{ entry.group.label }}</span>\n @if (showGroupCount()) {\n <span class=\"wr-table__group-count\">{{ entry.group.count }}</span>\n }\n </button>\n }\n </div>\n </td>\n </tr>\n } @else if (entry.kind === 'group-foot') {\n <tr class=\"wr-table__group-foot-row\">\n @if (rowSelection()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @if (expandable()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @for (col of displayColumns(); track col.key) {\n <td\n class=\"wr-table__foot-cell\"\n [class.wr-table__td--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__td--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__td--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__td--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n >\n {{ entry.summaries.get(col.key) ?? '' }}\n </td>\n }\n </tr>\n } @else {\n <tr\n class=\"wr-table__tr\"\n [class.wr-table__tr--selected]=\"rowSelection() && isRowSelected(entry.row)\"\n [attr.aria-rowindex]=\"virtualized() ? windowStart() + i + 2 : null\"\n >\n @if (rowSelection()) {\n <td class=\"wr-table__td wr-table__td--select\">\n <wr-checkbox\n size=\"sm\"\n [ngModel]=\"isRowSelected(entry.row)\"\n (ngModelChange)=\"toggleRow(entry.row, $event)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @if (expandable()) {\n <td class=\"wr-table__td wr-table__td--expand\">\n <button\n type=\"button\"\n class=\"wr-table__expand-btn\"\n [class.wr-table__expand-btn--open]=\"isExpanded(entry.row)\"\n [attr.aria-expanded]=\"isExpanded(entry.row)\"\n aria-label=\"Toggle row details\"\n (click)=\"toggleExpand(entry.row)\"\n >\n <svg\n class=\"wr-icon__svg wr-table__expand-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n </td>\n }\n @for (col of displayColumns(); track col.key) {\n <td\n class=\"wr-table__td\"\n [class.wr-table__td--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__td--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__td--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__td--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n [attr.data-label]=\"col.column.title\"\n >\n @if (templateFor(col.key); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"cellContext(entry.row, col.key, col.column)\"\n />\n } @else {\n {{ getValue(entry.row, col.key) }}\n }\n </td>\n }\n </tr>\n @if (expandable() && isExpanded(entry.row)) {\n <tr class=\"wr-table__detail-row\">\n <td class=\"wr-table__detail\" [attr.colspan]=\"totalCols()\">\n <ng-container\n [ngTemplateOutlet]=\"expandTemplate() ?? null\"\n [ngTemplateOutletContext]=\"expandContext(entry.row)\"\n />\n </td>\n </tr>\n }\n }\n } @empty {\n <tr>\n <td class=\"wr-table__empty\" [attr.colspan]=\"totalCols()\">No data</td>\n </tr>\n }\n @if (virtualized() && virtualWindow().padBottom > 0) {\n <tr class=\"wr-table__spacer\" aria-hidden=\"true\">\n <td [attr.colspan]=\"totalCols()\" [style.height.px]=\"virtualWindow().padBottom\"></td>\n </tr>\n }\n }\n </tbody>\n\n @if (hasSummary() && items()?.length) {\n <tfoot>\n <tr class=\"wr-table__foot-row\">\n @if (rowSelection()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @if (expandable()) {\n <td class=\"wr-table__foot-cell wr-table__foot-cell--lead\"></td>\n }\n @for (col of displayColumns(); track col.key) {\n <td\n class=\"wr-table__foot-cell\"\n [class.wr-table__td--pin-left]=\"col.column.pin === 'left'\"\n [class.wr-table__td--pin-right]=\"col.column.pin === 'right'\"\n [class.wr-table__td--pin-edge-left]=\"isPinEdge(col.key, 'left')\"\n [class.wr-table__td--pin-edge-right]=\"isPinEdge(col.key, 'right')\"\n [style.left.px]=\"leftPin(col.key)\"\n [style.right.px]=\"rightPin(col.key)\"\n >\n {{ summaryFor(col.key) }}\n </td>\n }\n </tr>\n </tfoot>\n }\n </table>\n</div>\n\n@if (showPager()) {\n <div class=\"wr-table__pager\">\n <wr-pagination [(currentPage)]=\"page\" [pageSize]=\"pageSize()\" [total]=\"resolvedTotal()\" />\n </div>\n}\n" }]
1072
+ }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], responsive: [{ type: i0.Input, args: [{ isSignal: true, alias: "responsive", required: false }] }], reorderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderable", required: false }] }], columnOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnOrder", required: false }] }, { type: i0.Output, args: ["columnOrderChange"] }], rowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelection", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }, { type: i0.Output, args: ["selectionChange"] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], collapsedGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedGroups", required: false }] }, { type: i0.Output, args: ["collapsedGroupsChange"] }], groupSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupSummary", required: false }] }], showGroupCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGroupCount", required: false }] }], sort: [{ type: i0.Input, args: [{ isSignal: true, alias: "sort", required: false }] }, { type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], totalItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalItems", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], viewportHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportHeight", required: false }] }], overscan: [{ type: i0.Input, args: [{ isSignal: true, alias: "overscan", required: false }] }], cellTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => WrTableCell), { isSignal: true }] }], headerCells: [{ type: i0.ViewChildren, args: ['thCell', { isSignal: true }] }], scrollEl: [{ type: i0.ViewChild, args: ['scroll', { isSignal: true }] }], expandTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => WrTableExpand), { isSignal: true }] }], groupTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => WrTableGroupHeader), { isSignal: true }] }] } });
269
1073
 
270
1074
  /**
271
1075
  * Generated bundle index. Do not edit.
272
1076
  */
273
1077
 
274
- export { WrTable, WrTableCell, WrTableFilter, WrTableSort };
1078
+ export { WrTable, WrTableCell, WrTableExpand, WrTableFilter, WrTableGroupHeader, WrTableSort };
275
1079
  //# sourceMappingURL=ngwr-table.mjs.map