ngwr 11.2.0 → 12.1.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 (395) hide show
  1. package/README.md +85 -26
  2. package/burger/styles/_index.scss +1 -1
  3. package/button/styles/_index.scss +2 -2
  4. package/calendar/styles/_index.scss +32 -12
  5. package/calendar-heatmap/styles/_index.scss +20 -0
  6. package/carousel/styles/_index.scss +23 -1
  7. package/cascader/styles/_index.scss +15 -3
  8. package/checkbox/styles/_index.scss +2 -2
  9. package/collapse/styles/_index.scss +2 -2
  10. package/color-picker/styles/_index.scss +3 -3
  11. package/compare/styles/_index.scss +18 -2
  12. package/context-menu/styles/_index.scss +21 -2
  13. package/date-picker/styles/_index.scss +5 -5
  14. package/descriptions/styles/_index.scss +1 -1
  15. package/drag-drop/styles/_index.scss +28 -1
  16. package/drawer/styles/_index.scss +37 -0
  17. package/dropdown/styles/_index.scss +2 -2
  18. package/event-calendar/styles/_index.scss +67 -10
  19. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  20. package/fesm2022/ngwr-affix.mjs +3 -3
  21. package/fesm2022/ngwr-alert.mjs +3 -3
  22. package/fesm2022/ngwr-anchor.mjs +3 -3
  23. package/fesm2022/ngwr-aurora.mjs +3 -3
  24. package/fesm2022/ngwr-avatar.mjs +3 -3
  25. package/fesm2022/ngwr-back-top.mjs +3 -3
  26. package/fesm2022/ngwr-badge.mjs +6 -6
  27. package/fesm2022/ngwr-bar-chart-testing.mjs +20 -2
  28. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  29. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  30. package/fesm2022/ngwr-blur-text.mjs +3 -3
  31. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  32. package/fesm2022/ngwr-border-glow.mjs +4 -4
  33. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  34. package/fesm2022/ngwr-breadcrumbs.mjs +29 -17
  35. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  36. package/fesm2022/ngwr-burger.mjs +3 -3
  37. package/fesm2022/ngwr-button.mjs +6 -6
  38. package/fesm2022/ngwr-calendar-heatmap.mjs +17 -5
  39. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  40. package/fesm2022/ngwr-calendar-testing.mjs +1 -1
  41. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  42. package/fesm2022/ngwr-calendar.mjs +187 -9
  43. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  44. package/fesm2022/ngwr-card.mjs +10 -10
  45. package/fesm2022/ngwr-card.mjs.map +1 -1
  46. package/fesm2022/ngwr-carousel.mjs +124 -24
  47. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  48. package/fesm2022/ngwr-cascader.mjs +48 -5
  49. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  50. package/fesm2022/ngwr-checkbox.mjs +6 -6
  51. package/fesm2022/ngwr-circular-text.mjs +4 -4
  52. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  53. package/fesm2022/ngwr-click-spark.mjs +27 -7
  54. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  55. package/fesm2022/ngwr-clipboard.mjs +3 -3
  56. package/fesm2022/ngwr-collapse.mjs +9 -9
  57. package/fesm2022/ngwr-color-picker-testing.mjs +26 -6
  58. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  59. package/fesm2022/ngwr-color-picker.mjs +98 -8
  60. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  61. package/fesm2022/ngwr-command-palette.mjs +14 -5
  62. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  63. package/fesm2022/ngwr-compare.mjs +3 -3
  64. package/fesm2022/ngwr-confetti.mjs +31 -6
  65. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  66. package/fesm2022/ngwr-config.mjs +9 -0
  67. package/fesm2022/ngwr-config.mjs.map +1 -1
  68. package/fesm2022/ngwr-context-menu-testing.mjs +30 -11
  69. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-context-menu.mjs +333 -43
  71. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  72. package/fesm2022/ngwr-cookie.mjs +3 -3
  73. package/fesm2022/ngwr-counter.mjs +25 -9
  74. package/fesm2022/ngwr-counter.mjs.map +1 -1
  75. package/fesm2022/{ngwr-date-adapter-fns.mjs → ngwr-date-adapters-fns.mjs} +37 -10
  76. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -0
  77. package/fesm2022/{ngwr-date-adapter-luxon.mjs → ngwr-date-adapters-luxon.mjs} +5 -5
  78. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -0
  79. package/fesm2022/ngwr-date-picker-testing.mjs +11 -6
  80. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  81. package/fesm2022/ngwr-date-picker.mjs +119 -37
  82. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  83. package/fesm2022/{ngwr-date-adapter.mjs → ngwr-date.mjs} +36 -10
  84. package/fesm2022/ngwr-date.mjs.map +1 -0
  85. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  86. package/fesm2022/ngwr-density.mjs +6 -6
  87. package/fesm2022/ngwr-descriptions.mjs +6 -6
  88. package/fesm2022/ngwr-dialog.mjs +73 -18
  89. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  90. package/fesm2022/ngwr-directives.mjs +12 -12
  91. package/fesm2022/ngwr-divider.mjs +52 -5
  92. package/fesm2022/ngwr-divider.mjs.map +1 -1
  93. package/fesm2022/ngwr-donut-chart-testing.mjs +8 -4
  94. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  95. package/fesm2022/ngwr-donut-chart.mjs +7 -7
  96. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  97. package/fesm2022/ngwr-drag-drop.mjs +160 -11
  98. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  99. package/fesm2022/ngwr-drawer.mjs +121 -58
  100. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  101. package/fesm2022/ngwr-dropdown.mjs +26 -10
  102. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  103. package/fesm2022/ngwr-empty.mjs +3 -3
  104. package/fesm2022/ngwr-event-calendar.mjs +28 -15
  105. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  106. package/fesm2022/ngwr-falling-text-testing.mjs +5 -3
  107. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  108. package/fesm2022/ngwr-falling-text.mjs +75 -46
  109. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  110. package/fesm2022/ngwr-file-upload.mjs +3 -3
  111. package/fesm2022/ngwr-form.mjs +32 -15
  112. package/fesm2022/ngwr-form.mjs.map +1 -1
  113. package/fesm2022/ngwr-fuzzy-text.mjs +21 -11
  114. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  115. package/fesm2022/ngwr-gauge.mjs +3 -3
  116. package/fesm2022/ngwr-glitch-text-testing.mjs +51 -17
  117. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  118. package/fesm2022/ngwr-glitch-text.mjs +7 -7
  119. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  120. package/fesm2022/ngwr-gradient-text-testing.mjs +46 -11
  121. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  122. package/fesm2022/ngwr-gradient-text.mjs +4 -4
  123. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  124. package/fesm2022/ngwr-hotkey.mjs +24 -9
  125. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  126. package/fesm2022/ngwr-i18n-en.mjs +73 -1
  127. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  128. package/fesm2022/ngwr-i18n-ru.mjs +55 -1
  129. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  130. package/fesm2022/ngwr-i18n.mjs +26 -15
  131. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  132. package/fesm2022/ngwr-icon.mjs +6 -6
  133. package/fesm2022/ngwr-image-cropper-testing.mjs +53 -9
  134. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  135. package/fesm2022/ngwr-image-cropper.mjs +150 -12
  136. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  137. package/fesm2022/ngwr-input-number-testing.mjs +15 -10
  138. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  139. package/fesm2022/ngwr-input-number.mjs +17 -10
  140. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  141. package/fesm2022/ngwr-input-otp-testing.mjs +12 -6
  142. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  143. package/fesm2022/ngwr-input-otp.mjs +24 -5
  144. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  145. package/fesm2022/ngwr-input.mjs +15 -15
  146. package/fesm2022/ngwr-keyboard.mjs +3 -3
  147. package/fesm2022/ngwr-knob.mjs +3 -3
  148. package/fesm2022/ngwr-layout.mjs +15 -15
  149. package/fesm2022/ngwr-lightbox.mjs +4 -4
  150. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  151. package/fesm2022/ngwr-line-chart.mjs +73 -26
  152. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  153. package/fesm2022/ngwr-list.mjs +7 -7
  154. package/fesm2022/ngwr-list.mjs.map +1 -1
  155. package/fesm2022/ngwr-loading-bar.mjs +7 -7
  156. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  157. package/fesm2022/ngwr-markdown.mjs +66 -8
  158. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  159. package/fesm2022/ngwr-marquee.mjs +4 -4
  160. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  161. package/fesm2022/ngwr-media.mjs +3 -3
  162. package/fesm2022/ngwr-mention.mjs +108 -13
  163. package/fesm2022/ngwr-mention.mjs.map +1 -1
  164. package/fesm2022/ngwr-meta.mjs +6 -6
  165. package/fesm2022/ngwr-meter-group-testing.mjs +26 -6
  166. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  167. package/fesm2022/ngwr-meter-group.mjs +3 -3
  168. package/fesm2022/ngwr-overlay.mjs +6 -6
  169. package/fesm2022/ngwr-page-header.mjs +3 -3
  170. package/fesm2022/ngwr-pagination-testing.mjs +6 -6
  171. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  172. package/fesm2022/ngwr-pagination.mjs +83 -16
  173. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  174. package/fesm2022/ngwr-pipes.mjs +39 -26
  175. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  176. package/fesm2022/ngwr-platform.mjs +9 -9
  177. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  178. package/fesm2022/ngwr-popover-testing.mjs +7 -2
  179. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  180. package/fesm2022/ngwr-popover.mjs +155 -33
  181. package/fesm2022/ngwr-popover.mjs.map +1 -1
  182. package/fesm2022/ngwr-progress.mjs +3 -3
  183. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  184. package/fesm2022/ngwr-qr.mjs +42 -5
  185. package/fesm2022/ngwr-qr.mjs.map +1 -1
  186. package/fesm2022/ngwr-radio.mjs +6 -6
  187. package/fesm2022/ngwr-rating.mjs +3 -3
  188. package/fesm2022/ngwr-result.mjs +21 -30
  189. package/fesm2022/ngwr-result.mjs.map +1 -1
  190. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  191. package/fesm2022/ngwr-scroll.mjs +3 -3
  192. package/fesm2022/ngwr-segmented-testing.mjs +85 -1
  193. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  194. package/fesm2022/ngwr-segmented.mjs +123 -10
  195. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  196. package/fesm2022/ngwr-select.mjs +159 -34
  197. package/fesm2022/ngwr-select.mjs.map +1 -1
  198. package/fesm2022/ngwr-shiny-text.mjs +11 -9
  199. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  200. package/fesm2022/ngwr-sidebar.mjs +31 -16
  201. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  202. package/fesm2022/ngwr-skeleton.mjs +3 -3
  203. package/fesm2022/ngwr-slider.mjs +100 -9
  204. package/fesm2022/ngwr-slider.mjs.map +1 -1
  205. package/fesm2022/ngwr-sparkline.mjs +3 -3
  206. package/fesm2022/ngwr-speed-dial-testing.mjs +15 -13
  207. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  208. package/fesm2022/ngwr-speed-dial.mjs +27 -12
  209. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  210. package/fesm2022/ngwr-spinner.mjs +3 -3
  211. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  212. package/fesm2022/ngwr-split-text.mjs +17 -5
  213. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  214. package/fesm2022/ngwr-splitter.mjs +3 -3
  215. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  216. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  217. package/fesm2022/ngwr-squircle.mjs +6 -6
  218. package/fesm2022/ngwr-star-border.mjs +4 -4
  219. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  220. package/fesm2022/ngwr-statistic.mjs +9 -9
  221. package/fesm2022/ngwr-stepper-testing.mjs +8 -8
  222. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  223. package/fesm2022/ngwr-stepper.mjs +33 -8
  224. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  225. package/fesm2022/ngwr-storage.mjs +17 -5
  226. package/fesm2022/ngwr-storage.mjs.map +1 -1
  227. package/fesm2022/ngwr-switch.mjs +3 -3
  228. package/fesm2022/ngwr-table.mjs +99 -39
  229. package/fesm2022/ngwr-table.mjs.map +1 -1
  230. package/fesm2022/ngwr-tabs-testing.mjs +11 -10
  231. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  232. package/fesm2022/ngwr-tabs.mjs +36 -10
  233. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  234. package/fesm2022/ngwr-textarea.mjs +3 -3
  235. package/fesm2022/ngwr-theme.mjs +181 -4
  236. package/fesm2022/ngwr-theme.mjs.map +1 -1
  237. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  238. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  239. package/fesm2022/ngwr-timeline.mjs +6 -6
  240. package/fesm2022/ngwr-toast.mjs +9 -9
  241. package/fesm2022/ngwr-toolbar.mjs +3 -3
  242. package/fesm2022/ngwr-tour.mjs +34 -10
  243. package/fesm2022/ngwr-tour.mjs.map +1 -1
  244. package/fesm2022/ngwr-transfer.mjs +3 -3
  245. package/fesm2022/ngwr-tree.mjs +28 -10
  246. package/fesm2022/ngwr-tree.mjs.map +1 -1
  247. package/fesm2022/ngwr-typewriter-testing.mjs +15 -1
  248. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  249. package/fesm2022/ngwr-typewriter.mjs +13 -5
  250. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  251. package/fesm2022/ngwr-typography.mjs +3 -3
  252. package/fesm2022/ngwr-utils.mjs +5 -2
  253. package/fesm2022/ngwr-utils.mjs.map +1 -1
  254. package/fesm2022/ngwr-version.mjs +1 -1
  255. package/fesm2022/ngwr-version.mjs.map +1 -1
  256. package/fesm2022/ngwr-virtual-scroll.mjs +4 -4
  257. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  258. package/fesm2022/ngwr-waves.mjs +4 -4
  259. package/fesm2022/ngwr-waves.mjs.map +1 -1
  260. package/fesm2022/ngwr-window.mjs +94 -24
  261. package/fesm2022/ngwr-window.mjs.map +1 -1
  262. package/file-upload/styles/_index.scss +2 -2
  263. package/glitch-text/styles/_index.scss +27 -12
  264. package/i18n/en.json +56 -6
  265. package/i18n/ru.json +56 -6
  266. package/image-cropper/styles/_index.scss +19 -0
  267. package/input/styles/_index.scss +2 -2
  268. package/input-number/styles/_index.scss +2 -2
  269. package/input-otp/styles/_index.scss +9 -2
  270. package/knob/styles/_index.scss +1 -1
  271. package/lightbox/styles/_index.scss +16 -2
  272. package/line-chart/styles/_index.scss +28 -14
  273. package/list/styles/_index.scss +1 -1
  274. package/llms-full.txt +19 -24
  275. package/llms.txt +46 -8
  276. package/markdown/styles/_index.scss +3 -3
  277. package/mcp/api.js +6 -4
  278. package/mcp/catalog.js +40 -3
  279. package/mcp/providers.js +16 -3
  280. package/mcp/tools.js +21 -1
  281. package/meter-group/styles/_index.scss +1 -1
  282. package/overlay/styles/_index.scss +33 -1
  283. package/package.json +17 -12
  284. package/pagination/styles/_index.scss +23 -1
  285. package/popover/styles/_index.scss +16 -7
  286. package/progress/styles/_index.scss +1 -1
  287. package/radio/styles/_index.scss +2 -2
  288. package/rating/styles/_index.scss +1 -1
  289. package/schematics/collection.json +1 -1
  290. package/schematics/migrations/v12/index.js +65 -0
  291. package/schematics/migrations/v7/index.js +12 -1
  292. package/schematics/migrations/v8/index.js +10 -1
  293. package/schematics/migrations.json +5 -0
  294. package/schematics/ng-add/index.js +8 -3
  295. package/schematics/provider/index.js +80 -13
  296. package/schematics/use/index.js +9 -129
  297. package/schematics/use/rule.js +206 -0
  298. package/schematics/use/symbol-map.json +4 -4
  299. package/segmented/styles/_index.scss +14 -3
  300. package/select/styles/_index.scss +14 -2
  301. package/sidebar/styles/_index.scss +12 -10
  302. package/skills/ngwr/SKILL.md +7 -5
  303. package/skills/ngwr/references/catalog.md +9 -9
  304. package/skills/ngwr/references/setup.md +10 -5
  305. package/slider/styles/_index.scss +1 -1
  306. package/speed-dial/styles/_index.scss +1 -1
  307. package/stepper/styles/_index.scss +12 -3
  308. package/switch/styles/_index.scss +2 -2
  309. package/table/styles/_index.scss +61 -12
  310. package/tabs/styles/_index.scss +1 -1
  311. package/textarea/styles/_index.scss +1 -1
  312. package/theme/styles/_colors.scss +142 -56
  313. package/theme/styles/_dark.scss +46 -3
  314. package/theme/styles/_focus.scss +28 -5
  315. package/theme/styles/_mixins.scss +1 -1
  316. package/theme/styles/_variables.scss +67 -0
  317. package/transfer/styles/_index.scss +26 -3
  318. package/tree/styles/_index.scss +29 -6
  319. package/types/ngwr-bar-chart-testing.d.ts +9 -1
  320. package/types/ngwr-blur-text.d.ts +8 -4
  321. package/types/ngwr-breadcrumbs.d.ts +17 -10
  322. package/types/ngwr-calendar-testing.d.ts +1 -1
  323. package/types/ngwr-calendar.d.ts +66 -0
  324. package/types/ngwr-carousel.d.ts +85 -6
  325. package/types/ngwr-cascader.d.ts +17 -0
  326. package/types/ngwr-click-spark.d.ts +4 -0
  327. package/types/ngwr-color-picker-testing.d.ts +8 -0
  328. package/types/ngwr-color-picker.d.ts +21 -1
  329. package/types/ngwr-confetti.d.ts +8 -0
  330. package/types/ngwr-config.d.ts +10 -1
  331. package/types/ngwr-context-menu-testing.d.ts +24 -11
  332. package/types/ngwr-context-menu.d.ts +56 -0
  333. package/types/ngwr-counter.d.ts +1 -0
  334. package/types/{ngwr-date-adapter-fns.d.ts → ngwr-date-adapters-fns.d.ts} +33 -6
  335. package/types/{ngwr-date-adapter-luxon.d.ts → ngwr-date-adapters-luxon.d.ts} +1 -1
  336. package/types/ngwr-date-picker-testing.d.ts +11 -6
  337. package/types/ngwr-date-picker.d.ts +8 -4
  338. package/types/{ngwr-date-adapter.d.ts → ngwr-date.d.ts} +24 -5
  339. package/types/ngwr-dialog.d.ts +38 -1
  340. package/types/ngwr-divider.d.ts +25 -0
  341. package/types/ngwr-donut-chart-testing.d.ts +7 -3
  342. package/types/ngwr-donut-chart.d.ts +3 -3
  343. package/types/ngwr-drag-drop.d.ts +56 -2
  344. package/types/ngwr-drawer.d.ts +56 -5
  345. package/types/ngwr-event-calendar.d.ts +8 -2
  346. package/types/ngwr-falling-text-testing.d.ts +5 -3
  347. package/types/ngwr-falling-text.d.ts +1 -1
  348. package/types/ngwr-form.d.ts +12 -2
  349. package/types/ngwr-glitch-text-testing.d.ts +37 -8
  350. package/types/ngwr-gradient-text-testing.d.ts +16 -3
  351. package/types/ngwr-i18n.d.ts +13 -4
  352. package/types/ngwr-image-cropper-testing.d.ts +49 -10
  353. package/types/ngwr-image-cropper.d.ts +70 -5
  354. package/types/ngwr-input-number-testing.d.ts +15 -10
  355. package/types/ngwr-input-number.d.ts +11 -4
  356. package/types/ngwr-input-otp-testing.d.ts +12 -6
  357. package/types/ngwr-input-otp.d.ts +15 -1
  358. package/types/ngwr-line-chart.d.ts +20 -3
  359. package/types/ngwr-markdown.d.ts +11 -0
  360. package/types/ngwr-mention.d.ts +32 -0
  361. package/types/ngwr-meter-group-testing.d.ts +12 -2
  362. package/types/ngwr-overlay.d.ts +1 -0
  363. package/types/ngwr-pagination-testing.d.ts +4 -4
  364. package/types/ngwr-pagination.d.ts +11 -0
  365. package/types/ngwr-pipes.d.ts +1 -1
  366. package/types/ngwr-popover-testing.d.ts +7 -2
  367. package/types/ngwr-popover.d.ts +1 -0
  368. package/types/ngwr-result.d.ts +6 -0
  369. package/types/ngwr-segmented-testing.d.ts +53 -0
  370. package/types/ngwr-segmented.d.ts +107 -5
  371. package/types/ngwr-select.d.ts +68 -6
  372. package/types/ngwr-shiny-text.d.ts +4 -2
  373. package/types/ngwr-sidebar.d.ts +14 -5
  374. package/types/ngwr-slider.d.ts +69 -1
  375. package/types/ngwr-speed-dial-testing.d.ts +15 -11
  376. package/types/ngwr-speed-dial.d.ts +22 -3
  377. package/types/ngwr-split-text.d.ts +9 -0
  378. package/types/ngwr-stepper-testing.d.ts +5 -5
  379. package/types/ngwr-stepper.d.ts +8 -0
  380. package/types/ngwr-storage.d.ts +1 -0
  381. package/types/ngwr-table.d.ts +104 -11
  382. package/types/ngwr-tabs-testing.d.ts +11 -10
  383. package/types/ngwr-tabs.d.ts +2 -0
  384. package/types/ngwr-theme.d.ts +82 -1
  385. package/types/ngwr-tour.d.ts +22 -4
  386. package/types/ngwr-tree.d.ts +5 -4
  387. package/types/ngwr-typewriter-testing.d.ts +10 -0
  388. package/types/ngwr-utils.d.ts +5 -2
  389. package/types/ngwr-version.d.ts +1 -1
  390. package/types/ngwr-window.d.ts +39 -11
  391. package/typography/styles/_index.scss +1 -1
  392. package/window/styles/_index.scss +72 -26
  393. package/fesm2022/ngwr-date-adapter-fns.mjs.map +0 -1
  394. package/fesm2022/ngwr-date-adapter-luxon.mjs.map +0 -1
  395. package/fesm2022/ngwr-date-adapter.mjs.map +0 -1
@@ -9,6 +9,71 @@ import { Directionality } from '@angular/cdk/bidi';
9
9
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
10
10
  import { WrIcon } from 'ngwr/icon';
11
11
 
12
+ /**
13
+ * @license
14
+ *
15
+ * Use of this source code is governed by an MIT-style license that can be
16
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
17
+ */
18
+ /**
19
+ * Roving focus inside ONE context-menu pane.
20
+ *
21
+ * The APG menu pattern makes a menu a single tab stop and moves a focus cursor
22
+ * between its rows with the arrows — which is why every `<wr-context-menu-item>`
23
+ * carries `tabindex="-1"`. Shared by the root directive and by
24
+ * `WrContextMenuItem`'s submenu because a submenu is a SEPARATE overlay pane
25
+ * rather than nested DOM: each pane roves over its own rows, and CDK's keyboard
26
+ * dispatcher hands the key to the topmost one, which is the pane the user is in.
27
+ *
28
+ * @internal
29
+ */
30
+ /**
31
+ * The rows of one pane the cursor may land on. Disabled rows are not stops —
32
+ * the same rule `WrDropdown` follows.
33
+ */
34
+ function wrMenuItems(pane) {
35
+ return Array.from(pane.querySelectorAll('.wr-context-menu-item:not(.wr-context-menu-item--disabled)'));
36
+ }
37
+ /** Focus the row at `index`, wrapping at both ends. A pane with no rows is left alone. */
38
+ function wrFocusMenuItemAt(pane, index) {
39
+ const items = wrMenuItems(pane);
40
+ if (items.length === 0)
41
+ return;
42
+ const clamped = ((index % items.length) + items.length) % items.length;
43
+ items[clamped]?.focus();
44
+ }
45
+ /**
46
+ * ArrowDown / ArrowUp / Home / End over one pane's rows. Returns `true` when the
47
+ * key was consumed, so a caller can leave every other key alone.
48
+ */
49
+ function wrHandleMenuNavigation(pane, event) {
50
+ const items = wrMenuItems(pane);
51
+ if (items.length === 0)
52
+ return false;
53
+ const active = document.activeElement;
54
+ // -1 when the keyboard is not on a row yet, which makes ArrowDown open at the
55
+ // first row and ArrowUp at the last.
56
+ const index = active instanceof HTMLElement ? items.indexOf(active) : -1;
57
+ switch (event.key) {
58
+ case 'ArrowDown':
59
+ wrFocusMenuItemAt(pane, index + 1);
60
+ break;
61
+ case 'ArrowUp':
62
+ wrFocusMenuItemAt(pane, index <= 0 ? items.length - 1 : index - 1);
63
+ break;
64
+ case 'Home':
65
+ wrFocusMenuItemAt(pane, 0);
66
+ break;
67
+ case 'End':
68
+ wrFocusMenuItemAt(pane, items.length - 1);
69
+ break;
70
+ default:
71
+ return false;
72
+ }
73
+ event.preventDefault();
74
+ return true;
75
+ }
76
+
12
77
  /**
13
78
  * @license
14
79
  *
@@ -67,9 +132,17 @@ class WrContextMenuItem {
67
132
  scrollStrategies = inject(ScrollStrategyOptions);
68
133
  destroyRef = inject(DestroyRef);
69
134
  submenuRef = null;
135
+ submenuKeys = null;
70
136
  openTimer = null;
71
137
  closeTimer = null;
72
138
  submenuOpen = false;
139
+ /**
140
+ * Whether the pending open was asked for by the keyboard (→ / Enter / Space)
141
+ * rather than by hover — only then does the submenu take focus, the same rule
142
+ * `wr-dropdown` applies to its own open. Sweeping the cursor across a row must
143
+ * show its submenu without yanking the caret out of it.
144
+ */
145
+ openedByKeyboard = false;
73
146
  /**
74
147
  * Id of the submenu's menu element while it is open, published on the item as
75
148
  * `aria-controls` — the same contract the root trigger keeps (see
@@ -128,6 +201,7 @@ class WrContextMenuItem {
128
201
  return;
129
202
  if (this.submenu()) {
130
203
  event.preventDefault();
204
+ this.openedByKeyboard = true;
131
205
  this.scheduleOpen(0);
132
206
  return;
133
207
  }
@@ -155,6 +229,7 @@ class WrContextMenuItem {
155
229
  if (this.disabled() || !this.submenu())
156
230
  return;
157
231
  event.preventDefault();
232
+ this.openedByKeyboard = true;
158
233
  this.scheduleOpen(0);
159
234
  }
160
235
  closeFromKey(event) {
@@ -168,6 +243,7 @@ class WrContextMenuItem {
168
243
  if (this.disabled() || !this.submenu())
169
244
  return;
170
245
  this.cancelClose();
246
+ this.openedByKeyboard = false;
171
247
  this.scheduleOpen(SUBMENU_OPEN_DELAY);
172
248
  }
173
249
  /** @internal Hover-out schedules a close with a grace window. */
@@ -257,9 +333,60 @@ class WrContextMenuItem {
257
333
  // when the cursor crosses the gap between item and submenu pane.
258
334
  pane.addEventListener('mouseenter', this.onSubmenuEnter);
259
335
  pane.addEventListener('mouseleave', this.onSubmenuLeave);
336
+ // While this pane is open it is the newest overlay that listens, so CDK's
337
+ // keyboard dispatcher hands it every keydown and the root menu's own handler
338
+ // stops seeing them. Which pane the keys then act on is decided in
339
+ // `onSubmenuKeydown`, not here: a hover open leaves the caret where it was.
340
+ this.submenuKeys = this.submenuRef.keydownEvents().subscribe(event => this.onSubmenuKeydown(event));
341
+ // A keyboard open walks INTO the submenu; a hover open only shows it.
342
+ if (this.openedByKeyboard)
343
+ wrFocusMenuItemAt(pane, 0);
260
344
  this.submenuOpen = true;
261
345
  WrContextMenuItem.openSubmenus.set(this.host.nativeElement, this);
262
346
  }
347
+ /**
348
+ * @internal Keys routed here while this submenu is the topmost overlay: the
349
+ * arrows walk the rows of the pane the caret is in, and Escape or the arrow
350
+ * pointing BACK the way the menu cascades steps out one level, returning the
351
+ * cursor to the row that owns the pane when the cursor was inside it.
352
+ *
353
+ * Escape closes this level only, not the whole chain — the APG's rule for a
354
+ * submenu. It reaches this handler rather than the root's because the
355
+ * dispatcher stops at the topmost overlay that listens, which is now this one.
356
+ *
357
+ * Which is also why the arrows are aimed at the pane holding the caret rather
358
+ * than at this one. The dispatcher routes by stacking order, not by focus, and
359
+ * a HOVER-opened submenu is topmost while focus is deliberately still on the
360
+ * root row the pointer swept off (see `openedByKeyboard`) — so ArrowDown used
361
+ * to jump into this pane's first row instead of moving down the menu the user
362
+ * is in. Same reason `wr-dropdown`'s menu handler checks ownership.
363
+ */
364
+ onSubmenuKeydown(event) {
365
+ const pane = this.submenuRef?.overlayElement;
366
+ if (!pane)
367
+ return;
368
+ // A row inside the pane already acted on this key — its own → into a deeper
369
+ // submenu, or Enter on a leaf. Re-handling it here would close the pane out
370
+ // from under the level it just opened.
371
+ if (event.defaultPrevented)
372
+ return;
373
+ const active = document.activeElement;
374
+ const focusedPane = active instanceof Element ? active.closest('.wr-context-menu-overlay') : null;
375
+ const back = this.isRtl() ? 'ArrowRight' : 'ArrowLeft';
376
+ if (event.key === 'Escape' || event.key === back) {
377
+ event.preventDefault();
378
+ this.disposeSubmenu(false);
379
+ // Onto the owning row only when the caret was in the pane just closed:
380
+ // dismissing a submenu the pointer opened must not drag it off the row the
381
+ // keyboard user is on.
382
+ if (focusedPane === pane)
383
+ this.host.nativeElement.focus();
384
+ return;
385
+ }
386
+ // Falls back to this pane when the caret is outside every menu — nothing
387
+ // else can answer, and the navigation opens at the first row from there.
388
+ wrHandleMenuNavigation(focusedPane ?? pane, event);
389
+ }
263
390
  /** Bound handlers (= preserves identity for removeEventListener). */
264
391
  onSubmenuEnter = () => {
265
392
  this.cancelClose();
@@ -336,6 +463,12 @@ class WrContextMenuItem {
336
463
  this.submenuRef = null;
337
464
  this.submenuOpen = false;
338
465
  this.submenuId.set(null);
466
+ // Now, not when the ref is finally disposed 220ms later: an overlay with a
467
+ // keydown subscriber is where CDK's dispatcher STOPS looking, so a pane
468
+ // still listening on its way out would swallow the arrows for the whole
469
+ // exit animation and the root menu would go dead for a quarter of a second.
470
+ this.submenuKeys?.unsubscribe();
471
+ this.submenuKeys = null;
339
472
  WrContextMenuItem.openSubmenus.delete(this.host.nativeElement);
340
473
  const pane = ref.overlayElement;
341
474
  pane.removeEventListener('mouseenter', this.onSubmenuEnter);
@@ -366,10 +499,10 @@ class WrContextMenuItem {
366
499
  isRtl() {
367
500
  return this.dir?.value === 'rtl';
368
501
  }
369
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
370
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrContextMenuItem, isStandalone: true, selector: "wr-context-menu-item", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, submenu: { classPropertyName: "submenu", publicName: "submenu", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem" }, listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave($event)", "click": "onClick()", "keydown.enter": "activate($event)", "keydown.space": "activate($event)", "keydown.arrowRight": "onArrowRight($event)", "keydown.arrowLeft": "onArrowLeft($event)" }, properties: { "class": "classes()", "attr.tabindex": "-1", "attr.aria-disabled": "disabled() ? true : null", "attr.aria-haspopup": "submenu() ? \"menu\" : null", "attr.aria-expanded": "submenu() ? (submenuOpen ? \"true\" : \"false\") : null", "attr.aria-controls": "submenuId()" } }, ngImport: i0, template: "@if (icon(); as name) {\n <wr-icon class=\"wr-context-menu-item__icon\" [name]=\"name\" size=\"14\" />\n}\n<span class=\"wr-context-menu-item__label\"><ng-content /></span>\n@if (submenu()) {\n <svg\n class=\"wr-icon__svg wr-context-menu-item__chevron\"\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}\n", dependencies: [{ kind: "component", type: WrIcon, selector: "wr-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None });
502
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
503
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrContextMenuItem, isStandalone: true, selector: "wr-context-menu-item", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, submenu: { classPropertyName: "submenu", publicName: "submenu", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "menuitem" }, listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave($event)", "click": "onClick()", "keydown.enter": "activate($event)", "keydown.space": "activate($event)", "keydown.arrowRight": "onArrowRight($event)", "keydown.arrowLeft": "onArrowLeft($event)" }, properties: { "class": "classes()", "attr.tabindex": "-1", "attr.aria-disabled": "disabled() ? true : null", "attr.aria-haspopup": "submenu() ? \"menu\" : null", "attr.aria-expanded": "submenu() ? (submenuOpen ? \"true\" : \"false\") : null", "attr.aria-controls": "submenuId()" } }, ngImport: i0, template: "@if (icon(); as name) {\n <wr-icon class=\"wr-context-menu-item__icon\" [name]=\"name\" size=\"14\" />\n}\n<span class=\"wr-context-menu-item__label\"><ng-content /></span>\n@if (submenu()) {\n <svg\n class=\"wr-icon__svg wr-context-menu-item__chevron\"\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}\n", dependencies: [{ kind: "component", type: WrIcon, selector: "wr-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None });
371
504
  }
372
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenuItem, decorators: [{
505
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuItem, decorators: [{
373
506
  type: Component,
374
507
  args: [{ selector: 'wr-context-menu-item', encapsulation: ViewEncapsulation.None, host: {
375
508
  role: 'menuitem',
@@ -395,6 +528,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
395
528
  * Use of this source code is governed by an MIT-style license that can be
396
529
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
397
530
  */
531
+ /**
532
+ * Where the menu may hang off the pointer, best first: down-and-inline-start of
533
+ * the cursor (what a native context menu does), then flipped up, then across,
534
+ * then both.
535
+ *
536
+ * The origin is a zero-size POINT, so every `originX` / `originY` resolves to
537
+ * the same coordinate and only the overlay's own corner varies. `overlayX:
538
+ * 'start'` is the logical corner: CDK resolves it against the ambient reading
539
+ * direction, so an RTL page opens the menu to the LEFT of the cursor without a
540
+ * second table.
541
+ */
542
+ const POINTER_POSITIONS = [
543
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'top' },
544
+ { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },
545
+ { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'top' },
546
+ { originX: 'start', originY: 'top', overlayX: 'end', overlayY: 'bottom' },
547
+ ];
548
+ /**
549
+ * The pointer as a CDK origin: a zero-size rect at the click, in VIEWPORT
550
+ * coordinates.
551
+ *
552
+ * Live getters rather than a snapshot, and that is the whole trick. The menu is
553
+ * anchored to the DOCUMENT — as the page scrolls it travels with the content it
554
+ * was opened over (native + PrimeNG behaviour) — while CDK positions against
555
+ * the viewport. Reading the scroll offset at `apply()` time is what converts one
556
+ * into the other, so a re-anchor is nothing but a request to re-apply.
557
+ */
558
+ function pointerOrigin(pageX, pageY) {
559
+ return {
560
+ width: 0,
561
+ height: 0,
562
+ get x() {
563
+ return pageX - window.scrollX;
564
+ },
565
+ get y() {
566
+ return pageY - window.scrollY;
567
+ },
568
+ };
569
+ }
398
570
  /**
399
571
  * Attach to any element to show a `<wr-context-menu>` at the pointer
400
572
  * position when the user right-clicks or otherwise sends a `contextmenu`
@@ -440,6 +612,18 @@ class WrContextMenu {
440
612
  openMenuId = signal(null, /* @ts-ignore */
441
613
  ...(ngDevMode ? [{ debugName: "openMenuId" }] : /* istanbul ignore next */ []));
442
614
  overlayRef = null;
615
+ /**
616
+ * The open menu's subscription to CDK's keyboard dispatcher, held so that
617
+ * `closeOverlay()` can drop it — see the unsubscribe there for why the pane's
618
+ * own disposal is 220 ms too late.
619
+ */
620
+ rootKeys = null;
621
+ /**
622
+ * Where the keyboard was at the moment this menu took it, so a close can put
623
+ * it back there. Null when it was nowhere in particular (`<body>`) or already
624
+ * inside a menu pane, neither of which is a place to return to.
625
+ */
626
+ restoreFocusTo = null;
443
627
  /**
444
628
  * Panes waiting out their exit animation, keyed by the timer that disposes
445
629
  * them.
@@ -590,37 +774,47 @@ class WrContextMenu {
590
774
  }
591
775
  // Overlay
592
776
  openOverlay(x, y) {
593
- // GlobalPositionStrategy uses margins, which led to flaky positioning
594
- // (`position: static` inline overridden by our `!important`, etc.).
595
- // Use it just to create the overlay, then write the coords directly to
596
- // the pane element via `top`/`left` so the menu sits exactly where the
597
- // user clicked and never moves until we close it.
777
+ // Read before `wrFocusMenuItemAt` below takes the keyboard: this is the
778
+ // element the close hands it back to. A pane row is not a candidate — a
779
+ // previous menu may still be fading out — and neither is `<body>`, which is
780
+ // where focus already is when nobody has it.
781
+ const active = document.activeElement;
782
+ this.restoreFocusTo =
783
+ active instanceof HTMLElement && active !== document.body && !active.closest('.wr-context-menu-overlay')
784
+ ? active
785
+ : null;
786
+ // Anchored to the POINTER, which is not an element — CDK takes a virtual
787
+ // origin for exactly that, and a FLEXIBLE strategy is what makes the menu
788
+ // flip up (or across) instead of hanging off the edge of the screen. It used
789
+ // to be a bare `GlobalPositionStrategy` with the raw coordinates written
790
+ // onto the pane, which never measured the menu against the viewport: a
791
+ // right-click 6px above the bottom of the window put two of the three rows
792
+ // below the fold and clipped the third, since the pane is `position: fixed`
793
+ // and cannot be scrolled to. Submenus have used the flexible strategy from
794
+ // the start (`context-menu-item.ts`); only the root skipped it.
795
+ const positionStrategy = this.overlay
796
+ .position()
797
+ .flexibleConnectedTo(pointerOrigin(x, y))
798
+ // The menu sizes itself; the fallbacks below are the whole answer to a
799
+ // cramped viewport, and `withPush` clamps whatever is left over.
800
+ .withFlexibleDimensions(false)
801
+ .withPush(true)
802
+ .withPositions(POINTER_POSITIONS);
598
803
  this.overlayRef = this.overlay.create({
599
- positionStrategy: this.overlay.position().global(),
600
- // `noop` so scroll doesn't dismiss the menu. With absolute coords
601
- // pinned to viewport (`position: fixed` in the panel CSS), the menu
602
- // visually stays put as the page scrolls underneath.
804
+ positionStrategy,
805
+ // `noop` so scroll doesn't dismiss the menu — `sync()` below re-anchors it
806
+ // instead.
603
807
  scrollStrategy: this.scrollStrategies.noop(),
604
808
  panelClass: ['wr-context-menu-overlay'],
605
809
  });
606
810
  const portal = new TemplatePortal(this.menu().contentTpl(), this.vcr);
607
811
  this.overlayRef.attach(portal);
608
- // Position model: the pane uses `position: fixed` (panel CSS) but we
609
- // want the menu to anchor to the DOCUMENT — when the user scrolls,
610
- // the menu should travel with the content it was opened over (native
611
- // browser + PrimeNG behavior). Strategy:
612
- //
613
- // - Record the page coords (pageX/pageY = document-relative).
614
- // - Each frame the user scrolls, set top/left to (pageX/Y minus the
615
- // current scroll offset). At scroll 0 this matches clientX/Y; as
616
- // scroll grows the menu shifts up/left visually, which is exactly
617
- // what `position: absolute` inside an un-fixed container would do
618
- // naturally — we just have to emulate it manually because CDK's
619
- // overlay container is `position: fixed`.
812
+ // `attach()` defers CDK's first placement into `afterNextRender`. Place it
813
+ // now: until then the pane sits at the container's top-left corner, and the
814
+ // rows are already in the DOM (see `wrFocusMenuItemAt` below), so the
815
+ // measurement the flip depends on is available.
816
+ this.overlayRef.updatePosition();
620
817
  const pane = this.overlayRef.overlayElement;
621
- pane.style.right = 'auto';
622
- pane.style.bottom = 'auto';
623
- pane.style.margin = '0';
624
818
  // Name the menu we just opened so the host can point at it. The id is
625
819
  // minted per OPEN rather than living on the panel: `closeOverlay()` keeps
626
820
  // the previous pane in the DOM for its exit animation, so a re-open would
@@ -631,11 +825,31 @@ class WrContextMenu {
631
825
  menuEl.id = randomId('wr-context-menu');
632
826
  this.openMenuId.set(menuEl.id);
633
827
  }
634
- const sync = () => {
635
- pane.style.top = `${y - window.scrollY}px`;
636
- pane.style.left = `${x - window.scrollX}px`;
637
- };
638
- sync();
828
+ // Re-anchor. `pointerOrigin` reads the scroll offset afresh, so this is all
829
+ // it takes for the menu to travel with the content it was opened over.
830
+ //
831
+ // `reapplyLastPosition()` rather than `updatePosition()`: the flip is
832
+ // decided once, when the menu opens. Re-running the fallback list on every
833
+ // scroll event would let the menu hop from above the cursor to below it and
834
+ // back while the page moves under it, which is a worse reading of "the menu
835
+ // stays where you put it" than a menu that simply slides with the page.
836
+ const sync = () => positionStrategy.reapplyLastPosition();
837
+ // Move the keyboard INTO the menu. Without this the pane painted a
838
+ // `role="menu"` that could be seen and never entered: rows are
839
+ // `tabindex="-1"` (the roving-focus contract) and the pane is not a tab
840
+ // stop, so ArrowDown / Enter / ArrowRight all went to whatever still held
841
+ // focus behind the menu and only Escape worked — the dispatcher routes that
842
+ // one regardless of focus.
843
+ //
844
+ // Unconditional, unlike `wr-dropdown`'s `openedByPointer` gate: there is no
845
+ // hover open here. Every path into this method is a deliberate request for
846
+ // the menu (right-click, Shift+F10, the Menu key, a long-press), which is
847
+ // also when a native context menu takes the keyboard.
848
+ //
849
+ // Synchronous, and it can be: `attach()` above runs the embedded view's
850
+ // first change detection itself (CDK's `attachTemplatePortal`), so the rows
851
+ // and their `[class]` host binding are already in the DOM.
852
+ wrFocusMenuItemAt(pane, 0);
639
853
  // Trigger the open transition on the next frame — adding the class
640
854
  // synchronously with attach would skip the initial 0→1 frame and
641
855
  // the menu would just appear without animating.
@@ -696,20 +910,39 @@ class WrContextMenu {
696
910
  return;
697
911
  this.closeOverlay();
698
912
  });
699
- this.overlayRef
913
+ this.rootKeys = this.overlayRef
700
914
  .keydownEvents()
701
915
  .pipe(takeUntilDestroyed(this.destroyRef))
702
916
  .subscribe(event => {
703
917
  if (event.key === 'Escape') {
704
918
  event.preventDefault();
705
919
  this.closeOverlay();
706
- this.host.nativeElement.focus();
920
+ return;
921
+ }
922
+ if (event.key === 'Tab') {
923
+ // Let focus leave naturally — `closeOverlay()` hands it back to the
924
+ // trigger first, so Tab continues from there instead of from a pane
925
+ // that is about to be removed.
926
+ this.closeOverlay();
927
+ return;
707
928
  }
929
+ // A row's own handler already acted on this key (ArrowRight into a
930
+ // submenu, Enter on an item): `preventDefault()` is how it says so, and
931
+ // moving the cursor on top of that would undo it.
932
+ if (event.defaultPrevented)
933
+ return;
934
+ wrHandleMenuNavigation(pane, event);
708
935
  });
709
936
  }
710
937
  closeOverlay() {
711
938
  if (!this.overlayRef)
712
939
  return;
940
+ // Read up front, before the teardown below starts on the panes: the answer
941
+ // wanted is where the keyboard was at the moment of dismissal.
942
+ const active = document.activeElement;
943
+ const focusWasInside = active instanceof Element && active.closest('.wr-context-menu-overlay') !== null;
944
+ const restoreTo = this.restoreFocusTo;
945
+ this.restoreFocusTo = null;
713
946
  this.cancelLeaveTimer();
714
947
  // Drop the reference immediately: the pane below stays in the DOM until the
715
948
  // exit animation has played, and a trigger still pointing at a menu on its
@@ -728,6 +961,25 @@ class WrContextMenu {
728
961
  // class first so the SCSS transition runs back to the default
729
962
  // (faded + scaled-down) state, then dispose after the transition.
730
963
  pane.classList.remove('wr-context-menu-overlay--open');
964
+ // …and stop it hit-testing on the way out. Fading to `opacity: 0` does not
965
+ // stop a pane receiving pointer events — `.cdk-overlay-pane` sets
966
+ // `pointer-events: auto` — so for the whole 220 ms an invisible menu kept
967
+ // swallowing clicks meant for the page underneath, and a second click on
968
+ // the item just picked (a double-click, or Escape then click) re-ran the
969
+ // consumer's action. Written inline rather than in `styles/_index.scss`
970
+ // because the closing state has no class of its own, and inline beats the
971
+ // CDK's own sheet without an `!important`.
972
+ pane.style.pointerEvents = 'none';
973
+ // …and stop it taking the page's KEYS on the way out, for the same reason
974
+ // and with the same timing. An overlay with a keydown subscriber is where
975
+ // CDK's dispatcher stops looking, and it is removed from the dispatcher only
976
+ // by `detach()` / `dispose()` — which is 220 ms away — so a dismissed menu
977
+ // went on swallowing every keydown on the page: ArrowDown pulled real focus
978
+ // back onto a row of the invisible pane, and a second Escape meant for the
979
+ // dialog underneath was `preventDefault`ed and did nothing.
980
+ // `WrContextMenuItem.disposeSubmenu()` does exactly this; the root had not.
981
+ this.rootKeys?.unsubscribe();
982
+ this.rootKeys = null;
731
983
  const timer = setTimeout(() => {
732
984
  this.closingPanes.delete(timer);
733
985
  ref.dispose();
@@ -736,6 +988,44 @@ class WrContextMenu {
736
988
  // Mark immediately so a subsequent right-click opens a fresh menu
737
989
  // rather than landing on the disposing one.
738
990
  this.overlayRef = null;
991
+ // Hand the keyboard back. The menu takes focus on open, so a dismissal that
992
+ // left it in the pane would strand it on `<body>` once the pane is disposed
993
+ // and the next Tab would restart at the top of the document. Only when the
994
+ // caret was actually in the chain: Escape reaches this overlay from anywhere
995
+ // on the page (CDK's dispatcher routes it by stacking order, not by focus),
996
+ // and a menu nobody was in must not steal the caret from a field they are.
997
+ if (focusWasInside)
998
+ this.handBackFocus(restoreTo);
999
+ }
1000
+ /**
1001
+ * Put the keyboard back where it came from.
1002
+ *
1003
+ * The element that had it when the menu opened comes first: a context menu
1004
+ * hangs on a REGION — a card, a table row — and Shift+F10 / the Menu key fires
1005
+ * `contextmenu` at whatever control inside it the user was actually on, which
1006
+ * is their place in the page.
1007
+ *
1008
+ * The trigger is the fallback, and it needs help to be one. `[wrContextMenu]`
1009
+ * adds no `tabindex` and every shape the docs ship is a plain `<div>`, so
1010
+ * `focus()` on it does nothing at all — the handback silently missed, leaving
1011
+ * the caret in the disposing pane and then on `<body>`, which is the outcome
1012
+ * the call is there to prevent. Lending it `tabindex="-1"` for the call and
1013
+ * taking that back on blur keeps the consumer's DOM as they wrote it; a
1014
+ * permanent `tabindex="0"` would make every right-clickable region a tab stop,
1015
+ * which is their decision and not the library's.
1016
+ */
1017
+ handBackFocus(previous) {
1018
+ const target = previous?.isConnected && !previous.closest('.wr-context-menu-overlay') ? previous : this.host.nativeElement;
1019
+ target.focus();
1020
+ // Asking whether it took, rather than deciding up front whether it can: the
1021
+ // focusability rules are wide (an `<a>` needs an href, a `<div>` needs a
1022
+ // tabindex, `inert`/`disabled` opt out) and `document.activeElement` answers
1023
+ // all of them at once.
1024
+ if (document.activeElement === target)
1025
+ return;
1026
+ target.setAttribute('tabindex', '-1');
1027
+ target.focus();
1028
+ target.addEventListener('blur', () => target.removeAttribute('tabindex'), { once: true });
739
1029
  }
740
1030
  cancelLeaveTimer() {
741
1031
  if (this.leaveTimer !== null) {
@@ -750,10 +1040,10 @@ class WrContextMenu {
750
1040
  this.closeOverlay();
751
1041
  }, WrContextMenu.LEAVE_DELAY);
752
1042
  }
753
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive });
754
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.1", type: WrContextMenu, isStandalone: true, selector: "[wrContextMenu]", inputs: { menu: { classPropertyName: "menu", publicName: "wrContextMenu", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "contextmenu": "onContextMenu($event)", "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp()", "pointercancel": "onPointerUp()" }, properties: { "attr.aria-controls": "openMenuId()" }, classAttribute: "wr-context-menu-host" }, ngImport: i0 });
1043
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1044
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.4", type: WrContextMenu, isStandalone: true, selector: "[wrContextMenu]", inputs: { menu: { classPropertyName: "menu", publicName: "wrContextMenu", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "contextmenu": "onContextMenu($event)", "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp()", "pointercancel": "onPointerUp()" }, properties: { "attr.aria-controls": "openMenuId()" }, classAttribute: "wr-context-menu-host" }, ngImport: i0 });
755
1045
  }
756
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenu, decorators: [{
1046
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenu, decorators: [{
757
1047
  type: Directive,
758
1048
  args: [{
759
1049
  selector: '[wrContextMenu]',
@@ -793,10 +1083,10 @@ class WrContextMenuPanel {
793
1083
  /** The internal template the directive portals into the overlay. @internal */
794
1084
  contentTpl = viewChild.required(TemplateRef, /* @ts-ignore */
795
1085
  ...(ngDevMode ? [{ debugName: "contentTpl" }] : /* istanbul ignore next */ []));
796
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenuPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
797
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.1", type: WrContextMenuPanel, isStandalone: true, selector: "wr-context-menu", host: { styleAttribute: "display:none" }, viewQueries: [{ propertyName: "contentTpl", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], exportAs: ["wrContextMenu"], ngImport: i0, template: '<ng-template><div class="wr-context-menu" role="menu"><ng-content /></div></ng-template>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
1086
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
1087
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: WrContextMenuPanel, isStandalone: true, selector: "wr-context-menu", host: { styleAttribute: "display:none" }, viewQueries: [{ propertyName: "contentTpl", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], exportAs: ["wrContextMenu"], ngImport: i0, template: '<ng-template><div class="wr-context-menu" role="menu"><ng-content /></div></ng-template>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
798
1088
  }
799
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenuPanel, decorators: [{
1089
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuPanel, decorators: [{
800
1090
  type: Component,
801
1091
  args: [{
802
1092
  selector: 'wr-context-menu',
@@ -829,10 +1119,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
829
1119
  * ```
830
1120
  */
831
1121
  class WrContextMenuDivider {
832
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenuDivider, deps: [], target: i0.ɵɵFactoryTarget.Component });
833
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: WrContextMenuDivider, isStandalone: true, selector: "wr-context-menu-divider", host: { attributes: { "role": "separator", "aria-orientation": "horizontal" }, classAttribute: "wr-context-menu-divider" }, ngImport: i0, template: '', isInline: true, encapsulation: i0.ViewEncapsulation.None });
1122
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuDivider, deps: [], target: i0.ɵɵFactoryTarget.Component });
1123
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.4", type: WrContextMenuDivider, isStandalone: true, selector: "wr-context-menu-divider", host: { attributes: { "role": "separator", "aria-orientation": "horizontal" }, classAttribute: "wr-context-menu-divider" }, ngImport: i0, template: '', isInline: true, encapsulation: i0.ViewEncapsulation.None });
834
1124
  }
835
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrContextMenuDivider, decorators: [{
1125
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuDivider, decorators: [{
836
1126
  type: Component,
837
1127
  args: [{
838
1128
  selector: 'wr-context-menu-divider',