ngwr 13.0.1 → 14.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/README.md +69 -13
  2. package/aurora/aurora.scss +1 -1
  3. package/aurora/styles/_dark.scss +21 -0
  4. package/aurora/styles/_index.scss +11 -30
  5. package/aurora/styles/_rules.scss +25 -0
  6. package/border-glow/styles/_dark.scss +46 -0
  7. package/border-glow/styles/_index.scss +5 -0
  8. package/border-glow/styles/_rules.scss +0 -31
  9. package/button/styles/_index.scss +16 -0
  10. package/color-picker/styles/_index.scss +43 -5
  11. package/event-calendar/styles/_index.scss +15 -0
  12. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  13. package/fesm2022/ngwr-affix.mjs +3 -3
  14. package/fesm2022/ngwr-alert.mjs +7 -7
  15. package/fesm2022/ngwr-alert.mjs.map +1 -1
  16. package/fesm2022/ngwr-anchor.mjs +3 -3
  17. package/fesm2022/ngwr-aurora.mjs +4 -4
  18. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  19. package/fesm2022/ngwr-avatar.mjs +3 -3
  20. package/fesm2022/ngwr-back-top.mjs +14 -4
  21. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  22. package/fesm2022/ngwr-badge.mjs +6 -6
  23. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  24. package/fesm2022/ngwr-blur-text.mjs +16 -5
  25. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  26. package/fesm2022/ngwr-border-glow.mjs +4 -4
  27. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  28. package/fesm2022/ngwr-breadcrumbs.mjs +7 -7
  29. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  30. package/fesm2022/ngwr-burger.mjs +3 -3
  31. package/fesm2022/ngwr-button.mjs +88 -10
  32. package/fesm2022/ngwr-button.mjs.map +1 -1
  33. package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
  34. package/fesm2022/ngwr-calendar-testing.mjs +15 -0
  35. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  36. package/fesm2022/ngwr-calendar.mjs +53 -7
  37. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  38. package/fesm2022/ngwr-card.mjs +9 -9
  39. package/fesm2022/ngwr-carousel.mjs +6 -6
  40. package/fesm2022/ngwr-cascader.mjs +4 -4
  41. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  42. package/fesm2022/ngwr-checkbox.mjs +6 -6
  43. package/fesm2022/ngwr-circular-text.mjs +23 -4
  44. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  45. package/fesm2022/ngwr-click-spark.mjs +3 -3
  46. package/fesm2022/ngwr-clipboard.mjs +3 -3
  47. package/fesm2022/ngwr-collapse.mjs +9 -9
  48. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  49. package/fesm2022/ngwr-color-picker-testing.mjs +23 -7
  50. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  51. package/fesm2022/ngwr-color-picker.mjs +93 -14
  52. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  53. package/fesm2022/ngwr-command-palette.mjs +29 -5
  54. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  55. package/fesm2022/ngwr-compare.mjs +3 -3
  56. package/fesm2022/ngwr-confetti.mjs +3 -3
  57. package/fesm2022/ngwr-context-menu.mjs +18 -12
  58. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  59. package/fesm2022/ngwr-cookie.mjs +3 -3
  60. package/fesm2022/ngwr-counter.mjs +6 -6
  61. package/fesm2022/ngwr-date-adapters-fns.mjs +104 -36
  62. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
  63. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  64. package/fesm2022/ngwr-date-picker-testing.mjs +10 -2
  65. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  66. package/fesm2022/ngwr-date-picker.mjs +118 -28
  67. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  68. package/fesm2022/ngwr-date.mjs +483 -82
  69. package/fesm2022/ngwr-date.mjs.map +1 -1
  70. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  71. package/fesm2022/ngwr-density.mjs +6 -6
  72. package/fesm2022/ngwr-descriptions.mjs +6 -6
  73. package/fesm2022/ngwr-dialog.mjs +15 -15
  74. package/fesm2022/ngwr-directives.mjs +12 -12
  75. package/fesm2022/ngwr-divider.mjs +3 -3
  76. package/fesm2022/ngwr-donut-chart.mjs +3 -3
  77. package/fesm2022/ngwr-drag-drop.mjs +37 -9
  78. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  79. package/fesm2022/ngwr-drawer.mjs +18 -18
  80. package/fesm2022/ngwr-dropdown.mjs +29 -12
  81. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  82. package/fesm2022/ngwr-empty.mjs +3 -3
  83. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
  84. package/fesm2022/ngwr-event-calendar.mjs +6 -6
  85. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  86. package/fesm2022/ngwr-falling-text.mjs +3 -3
  87. package/fesm2022/ngwr-file-upload.mjs +55 -15
  88. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  89. package/fesm2022/ngwr-form-testing.mjs +13 -7
  90. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  91. package/fesm2022/ngwr-form.mjs +44 -25
  92. package/fesm2022/ngwr-form.mjs.map +1 -1
  93. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  94. package/fesm2022/ngwr-gauge.mjs +3 -3
  95. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  96. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  97. package/fesm2022/ngwr-hotkey.mjs +6 -6
  98. package/fesm2022/ngwr-i18n-en.mjs +63 -1
  99. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  100. package/fesm2022/ngwr-i18n-ru.mjs +28 -1
  101. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  102. package/fesm2022/ngwr-i18n.mjs +159 -31
  103. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  104. package/fesm2022/ngwr-icon.mjs +6 -6
  105. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  106. package/fesm2022/ngwr-input-number.mjs +5 -5
  107. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  108. package/fesm2022/ngwr-input-otp.mjs +23 -5
  109. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  110. package/fesm2022/ngwr-input.mjs +37 -26
  111. package/fesm2022/ngwr-input.mjs.map +1 -1
  112. package/fesm2022/ngwr-keyboard.mjs +3 -3
  113. package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
  114. package/fesm2022/ngwr-knob.mjs +22 -4
  115. package/fesm2022/ngwr-knob.mjs.map +1 -1
  116. package/fesm2022/ngwr-layout.mjs +15 -15
  117. package/fesm2022/ngwr-lightbox.mjs +4 -4
  118. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  119. package/fesm2022/ngwr-line-chart.mjs +3 -3
  120. package/fesm2022/ngwr-list.mjs +7 -7
  121. package/fesm2022/ngwr-list.mjs.map +1 -1
  122. package/fesm2022/ngwr-loading-bar-router.mjs +73 -0
  123. package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -0
  124. package/fesm2022/ngwr-loading-bar.mjs +27 -38
  125. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  126. package/fesm2022/ngwr-markdown.mjs +6 -6
  127. package/fesm2022/ngwr-marquee.mjs +3 -3
  128. package/fesm2022/ngwr-media.mjs +3 -3
  129. package/fesm2022/ngwr-mention.mjs +109 -19
  130. package/fesm2022/ngwr-mention.mjs.map +1 -1
  131. package/fesm2022/ngwr-meta.mjs +6 -6
  132. package/fesm2022/ngwr-meter-group.mjs +3 -3
  133. package/fesm2022/ngwr-overlay.mjs +6 -6
  134. package/fesm2022/ngwr-page-header.mjs +3 -3
  135. package/fesm2022/ngwr-pagination-testing.mjs +11 -10
  136. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  137. package/fesm2022/ngwr-pagination.mjs +67 -32
  138. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  139. package/fesm2022/ngwr-pipes.mjs +21 -21
  140. package/fesm2022/ngwr-platform.mjs +9 -9
  141. package/fesm2022/ngwr-popconfirm.mjs +7 -6
  142. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  143. package/fesm2022/ngwr-popover.mjs +7 -6
  144. package/fesm2022/ngwr-popover.mjs.map +1 -1
  145. package/fesm2022/ngwr-progress.mjs +3 -3
  146. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  147. package/fesm2022/ngwr-qr.mjs +3 -3
  148. package/fesm2022/ngwr-radio.mjs +6 -6
  149. package/fesm2022/ngwr-rating.mjs +48 -22
  150. package/fesm2022/ngwr-rating.mjs.map +1 -1
  151. package/fesm2022/ngwr-result.mjs +12 -12
  152. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  153. package/fesm2022/ngwr-scroll.mjs +3 -3
  154. package/fesm2022/ngwr-segmented.mjs +12 -8
  155. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  156. package/fesm2022/ngwr-select.mjs +217 -59
  157. package/fesm2022/ngwr-select.mjs.map +1 -1
  158. package/fesm2022/ngwr-shiny-text.mjs +7 -7
  159. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  160. package/fesm2022/ngwr-sidebar.mjs +3 -3
  161. package/fesm2022/ngwr-skeleton.mjs +3 -3
  162. package/fesm2022/ngwr-slider.mjs +12 -8
  163. package/fesm2022/ngwr-slider.mjs.map +1 -1
  164. package/fesm2022/ngwr-sparkline.mjs +3 -3
  165. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  166. package/fesm2022/ngwr-spinner.mjs +3 -3
  167. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  168. package/fesm2022/ngwr-split-text.mjs +3 -3
  169. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
  170. package/fesm2022/ngwr-splitter.mjs +3 -3
  171. package/fesm2022/ngwr-spotlight-card.mjs +7 -7
  172. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  173. package/fesm2022/ngwr-squircle.mjs +7 -6
  174. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  175. package/fesm2022/ngwr-star-border.mjs +4 -4
  176. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  177. package/fesm2022/ngwr-statistic.mjs +44 -13
  178. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  179. package/fesm2022/ngwr-stepper.mjs +6 -6
  180. package/fesm2022/ngwr-storage.mjs +11 -3
  181. package/fesm2022/ngwr-storage.mjs.map +1 -1
  182. package/fesm2022/ngwr-switch.mjs +3 -3
  183. package/fesm2022/ngwr-table.mjs +51 -28
  184. package/fesm2022/ngwr-table.mjs.map +1 -1
  185. package/fesm2022/ngwr-tabs-router.mjs +158 -0
  186. package/fesm2022/ngwr-tabs-router.mjs.map +1 -0
  187. package/fesm2022/ngwr-tabs-testing.mjs +13 -11
  188. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  189. package/fesm2022/ngwr-tabs.mjs +104 -16
  190. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  191. package/fesm2022/ngwr-textarea.mjs +46 -6
  192. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  193. package/fesm2022/ngwr-theme.mjs +90 -4
  194. package/fesm2022/ngwr-theme.mjs.map +1 -1
  195. package/fesm2022/ngwr-tilt-card.mjs +7 -7
  196. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  197. package/fesm2022/ngwr-timeline.mjs +6 -6
  198. package/fesm2022/ngwr-toast.mjs +116 -11
  199. package/fesm2022/ngwr-toast.mjs.map +1 -1
  200. package/fesm2022/ngwr-toolbar.mjs +3 -3
  201. package/fesm2022/ngwr-tour.mjs +6 -6
  202. package/fesm2022/ngwr-tour.mjs.map +1 -1
  203. package/fesm2022/ngwr-transfer.mjs +4 -4
  204. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  205. package/fesm2022/ngwr-tree.mjs +35 -12
  206. package/fesm2022/ngwr-tree.mjs.map +1 -1
  207. package/fesm2022/ngwr-typewriter.mjs +3 -3
  208. package/fesm2022/ngwr-typography.mjs +3 -3
  209. package/fesm2022/ngwr-utils.mjs +37 -1
  210. package/fesm2022/ngwr-utils.mjs.map +1 -1
  211. package/fesm2022/ngwr-version.mjs +1 -1
  212. package/fesm2022/ngwr-version.mjs.map +1 -1
  213. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  214. package/fesm2022/ngwr-waves.mjs +4 -4
  215. package/fesm2022/ngwr-waves.mjs.map +1 -1
  216. package/fesm2022/ngwr-window-testing.mjs +10 -2
  217. package/fesm2022/ngwr-window-testing.mjs.map +1 -1
  218. package/fesm2022/ngwr-window.mjs +15 -15
  219. package/fesm2022/ngwr-window.mjs.map +1 -1
  220. package/i18n/en.json +33 -6
  221. package/i18n/ru.json +33 -6
  222. package/llms-full.txt +29 -20
  223. package/llms.txt +127 -25
  224. package/mcp/catalog.js +3 -3
  225. package/mcp/providers.js +11 -0
  226. package/package.json +9 -1
  227. package/schematics/migrations/v13/index.js +101 -0
  228. package/schematics/migrations/v14/index.js +422 -0
  229. package/schematics/migrations.json +10 -0
  230. package/schematics/page/templates.js +1 -1
  231. package/schematics/use/symbol-map.json +1 -0
  232. package/shiny-text/styles/_dark.scss +20 -0
  233. package/shiny-text/styles/_index.scss +5 -0
  234. package/shiny-text/styles/_rules.scss +0 -4
  235. package/skills/ngwr/SKILL.md +4 -1
  236. package/skills/ngwr/references/catalog.md +2 -0
  237. package/skills/ngwr/references/setup.md +4 -0
  238. package/spotlight-card/styles/_dark.scss +21 -0
  239. package/spotlight-card/styles/_index.scss +5 -0
  240. package/spotlight-card/styles/_rules.scss +0 -6
  241. package/star-border/styles/_dark.scss +21 -0
  242. package/star-border/styles/_index.scss +5 -0
  243. package/star-border/styles/_rules.scss +0 -5
  244. package/stepper/styles/_index.scss +19 -1
  245. package/textarea/styles/_index.scss +14 -6
  246. package/theme/styles/_colors.scss +102 -0
  247. package/theme/styles/_focus.scss +31 -1
  248. package/tilt-card/styles/_dark.scss +21 -0
  249. package/tilt-card/styles/_index.scss +5 -0
  250. package/tilt-card/styles/_rules.scss +0 -5
  251. package/toast/styles/_index.scss +12 -4
  252. package/types/ngwr-alert.d.ts +3 -3
  253. package/types/ngwr-blur-text.d.ts +8 -0
  254. package/types/ngwr-button.d.ts +45 -2
  255. package/types/ngwr-calendar-testing.d.ts +21 -4
  256. package/types/ngwr-calendar.d.ts +37 -0
  257. package/types/ngwr-circular-text.d.ts +9 -0
  258. package/types/ngwr-collapse.d.ts +19 -15
  259. package/types/ngwr-color-picker-testing.d.ts +10 -4
  260. package/types/ngwr-color-picker.d.ts +70 -2
  261. package/types/ngwr-command-palette.d.ts +14 -0
  262. package/types/ngwr-context-menu.d.ts +1 -1
  263. package/types/ngwr-date-adapters-fns.d.ts +71 -29
  264. package/types/ngwr-date-picker-testing.d.ts +206 -185
  265. package/types/ngwr-date-picker.d.ts +7 -0
  266. package/types/ngwr-date.d.ts +143 -13
  267. package/types/ngwr-drag-drop.d.ts +19 -0
  268. package/types/ngwr-dropdown.d.ts +18 -2
  269. package/types/ngwr-event-calendar-testing.d.ts +12 -9
  270. package/types/ngwr-file-upload.d.ts +31 -3
  271. package/types/ngwr-form-testing.d.ts +13 -7
  272. package/types/ngwr-form.d.ts +47 -12
  273. package/types/ngwr-i18n.d.ts +89 -7
  274. package/types/ngwr-input-number.d.ts +1 -1
  275. package/types/ngwr-input-otp.d.ts +3 -0
  276. package/types/ngwr-input.d.ts +13 -5
  277. package/types/ngwr-knob-testing.d.ts +8 -4
  278. package/types/ngwr-knob.d.ts +18 -0
  279. package/types/ngwr-loading-bar-router.d.ts +35 -0
  280. package/types/ngwr-loading-bar.d.ts +19 -9
  281. package/types/ngwr-mention.d.ts +13 -0
  282. package/types/ngwr-pagination-testing.d.ts +11 -10
  283. package/types/ngwr-pagination.d.ts +39 -10
  284. package/types/ngwr-popconfirm.d.ts +1 -1
  285. package/types/ngwr-popover.d.ts +1 -1
  286. package/types/ngwr-rating.d.ts +25 -4
  287. package/types/ngwr-segmented.d.ts +1 -0
  288. package/types/ngwr-select.d.ts +110 -19
  289. package/types/ngwr-slider.d.ts +1 -0
  290. package/types/ngwr-splitter-testing.d.ts +9 -4
  291. package/types/ngwr-squircle.d.ts +1 -1
  292. package/types/ngwr-statistic.d.ts +22 -2
  293. package/types/ngwr-storage.d.ts +39 -1
  294. package/types/ngwr-table.d.ts +24 -5
  295. package/types/ngwr-tabs-router.d.ts +67 -0
  296. package/types/ngwr-tabs-testing.d.ts +12 -10
  297. package/types/ngwr-tabs.d.ts +103 -6
  298. package/types/ngwr-textarea.d.ts +29 -0
  299. package/types/ngwr-theme.d.ts +92 -2
  300. package/types/ngwr-toast.d.ts +53 -0
  301. package/types/ngwr-tree.d.ts +10 -2
  302. package/types/ngwr-utils.d.ts +33 -1
  303. package/types/ngwr-version.d.ts +1 -1
  304. package/types/ngwr-window-testing.d.ts +11 -3
  305. package/types/ngwr-window.d.ts +11 -4
  306. package/waves/styles/_dark.scss +19 -0
  307. package/waves/styles/_index.scss +5 -0
  308. package/waves/styles/_rules.scss +0 -3
  309. package/window/styles/_index.scss +1 -1
@@ -105,6 +105,19 @@ declare class WrMention<T extends WrMentionItem = WrMentionItem> {
105
105
  private liveRegion;
106
106
  constructor();
107
107
  private announce;
108
+ /**
109
+ * True between `compositionstart` and `compositionend`.
110
+ *
111
+ * Detection must not run on the half-built text an IME leaves in the field:
112
+ * `@やま` is a reading on its way to `@山田`, and matching the reading opens a
113
+ * panel that then eats the Enter meant to accept the conversion. So the field
114
+ * is read once, on `compositionend`, when the text is real.
115
+ */
116
+ private composing;
117
+ /** @internal */
118
+ protected onCompositionStart(): void;
119
+ /** @internal */
120
+ protected onCompositionEnd(): void;
108
121
  /** @internal */
109
122
  protected onInput(): void;
110
123
  /** @internal */
@@ -20,11 +20,11 @@ interface WrPaginationHarnessFilters extends BaseHarnessFilters {
20
20
  readonly label?: string | RegExp;
21
21
  /**
22
22
  * Match the page the pager announces as current via `aria-current="page"`. A
23
- * pager announcing none — `currentPage` set below 1 — matches no value here
23
+ * pager announcing none — `page` set below 1 — matches no value here
24
24
  * rather than throwing, so one broken pager cannot fail a query for its
25
25
  * neighbour.
26
26
  */
27
- readonly currentPage?: number;
27
+ readonly page?: number;
28
28
  /** Match only enabled (`false`) or only disabled (`true`) pagers. */
29
29
  readonly disabled?: boolean;
30
30
  }
@@ -179,7 +179,7 @@ declare class WrPaginationHarness extends ComponentHarness {
179
179
  * The page the pager announces as current, from `aria-current="page"`.
180
180
  *
181
181
  * Throws when no cell claims it. The window always keeps the current page on the
182
- * strip, so getting here means `currentPage` is not one of the pages at all. The
182
+ * strip, so getting here means `page` is not one of the pages at all. The
183
183
  * component clamps a host write into `1..totalPages`, which leaves one survivor:
184
184
  * a fractional page, which is in range and matches no cell — and which leaves
185
185
  * every cell looking equally inactive to an assistive tech user.
@@ -191,7 +191,7 @@ declare class WrPaginationHarness extends ComponentHarness {
191
191
  * Throws when that page is not on the strip — a seven-slot window over twenty
192
192
  * pages simply has no cell for page 15, and a silent no-op there reads as
193
193
  * "navigation is broken" three assertions later. Step with {@link next} /
194
- * {@link previous}, or move the host's own `currentPage` model.
194
+ * {@link previous}, or move the host's own `page` model.
195
195
  *
196
196
  * A disabled pager is still clicked; the component's own guard is what refuses
197
197
  * the move, so assert the page rather than assume it. Clicking the CURRENT page
@@ -233,14 +233,15 @@ declare class WrPaginationHarness extends ComponentHarness {
233
233
  /** Whether the pager shows its "X–Y of Z" label (the `showTotal` input). */
234
234
  hasTotal(): Promise<boolean>;
235
235
  /**
236
- * The total label exactly as rendered, e.g. `1-10 of 95`.
236
+ * The total label exactly as rendered, e.g. `1–10 of 95`.
237
237
  *
238
- * Both halves are localizable — the word between range and total comes from
239
- * `ofLabel` or the `pagination.of` catalog entry — so a spec asserting the whole
240
- * string should own the copy it asserts.
238
+ * The WHOLE string is one catalog entry (`pagination.range`) and the three
239
+ * numbers in it are formatted per `LOCALE_ID`, so a spec asserting the literal
240
+ * owns both the copy and the locale it asserts under. Note the range separator
241
+ * is an en dash, not the ASCII hyphen this used to print.
241
242
  *
242
243
  * Throws when the label is not rendered, which is a `showTotal` that was never
243
- * set rather than a total of zero (a zero total still renders `0-0 of 0`).
244
+ * set rather than a total of zero (a zero total still renders `0–0 of 0`).
244
245
  */
245
246
  getTotalText(): Promise<string>;
246
247
  /** Whether the pager renders its page-size changer (the `showSizeChanger` input). */
@@ -277,7 +278,7 @@ declare class WrPaginationHarness extends ComponentHarness {
277
278
  * {@link getPageSize} reads them: `20 / page` and `20 / стр.` are the same option.
278
279
  * Throws when no option offers that size, naming what is on offer.
279
280
  *
280
- * Changing the size can move the page — the component pulls `currentPage` back
281
+ * Changing the size can move the page — the component pulls `page` back
281
282
  * when the new size leaves it past the end — so re-read {@link getCurrentPage}
282
283
  * afterwards rather than assuming it held.
283
284
  */
@@ -42,13 +42,13 @@ type PageEntry = number | typeof ELLIPSIS;
42
42
  /**
43
43
  * Numbered page navigator with optional total / page-size controls.
44
44
  *
45
- * Two-way binds `currentPage` and `pageSize` via signal `model()` inputs.
45
+ * Two-way binds `page` and `pageSize` via signal `model()` inputs.
46
46
  *
47
47
  * @example
48
48
  * ```html
49
49
  * <wr-pagination
50
50
  * [total]="120"
51
- * [(currentPage)]="page"
51
+ * [(page)]="page"
52
52
  * [(pageSize)]="size"
53
53
  * showTotal
54
54
  * showSizeChanger
@@ -58,8 +58,16 @@ type PageEntry = number | typeof ELLIPSIS;
58
58
  * @see https://ngwr.dev/reference/components/pagination
59
59
  */
60
60
  declare class WrPagination {
61
- /** Currently displayed page (1-based). Two-way bindable. */
62
- readonly currentPage: _angular_core.ModelSignal<number>;
61
+ /**
62
+ * Currently displayed page (1-based). Two-way bindable.
63
+ *
64
+ * `page` rather than `currentPage` since v14, so this and `<wr-table>` — which
65
+ * renders one of these in its own footer — spell the two concepts they share
66
+ * one way each. It also names the output: a `model()` called `X` forces
67
+ * `(XChange)`, so the old name produced `(currentPageChange)` against the
68
+ * table's `(pageChange)`.
69
+ */
70
+ readonly page: _angular_core.ModelSignal<number>;
63
71
  /** Items per page. Two-way bindable. */
64
72
  readonly pageSize: _angular_core.ModelSignal<number>;
65
73
  /** Total item count across all pages. */
@@ -84,8 +92,6 @@ declare class WrPagination {
84
92
  * width, not the viewport). @default false
85
93
  */
86
94
  readonly responsive: _angular_core.InputSignalWithTransform<boolean, any>;
87
- /** Localised text between range and total ("X–Y of Z"). Falls back to `pagination.of` then `'of'`. */
88
- readonly ofLabel: _angular_core.InputSignal<string | null>;
89
95
  /** Previous-page button aria-label. Falls back to `pagination.prev`. */
90
96
  readonly prevLabel: _angular_core.InputSignal<string | null>;
91
97
  /** Next-page button aria-label. Falls back to `pagination.next`. */
@@ -95,7 +101,6 @@ declare class WrPagination {
95
101
  /** Accessible name for the `role="navigation"` host. Falls back to `pagination.label`. */
96
102
  readonly label: _angular_core.InputSignal<string | null>;
97
103
  /** Resolved labels. */
98
- protected readonly resolvedOf: _angular_core.Signal<string>;
99
104
  protected readonly resolvedPrev: _angular_core.Signal<string>;
100
105
  protected readonly resolvedNext: _angular_core.Signal<string>;
101
106
  protected readonly resolvedItemsPerPage: _angular_core.Signal<string>;
@@ -113,7 +118,7 @@ declare class WrPagination {
113
118
  protected readonly totalPages: _angular_core.Signal<number>;
114
119
  /**
115
120
  * Internal: where the previous arrow goes. Clamped to the end of the valid
116
- * range rather than being a plain `currentPage() - 1`, because the page can
121
+ * range rather than being a plain `page() - 1`, because the page can
117
122
  * legitimately sit past that end while `total` is 0 (see the guard effect).
118
123
  * From page 5 of one page, `goTo(4)` is refused as out of range, so the arrow
119
124
  * was enabled and did nothing — and under `responsive` on a narrow box the
@@ -122,8 +127,32 @@ declare class WrPagination {
122
127
  * past-the-end refusal keeps working as the backstop it is.
123
128
  */
124
129
  protected readonly prevPage: _angular_core.Signal<number>;
125
- /** Internal: "X–Y of Z" string. */
130
+ /**
131
+ * Internal: the "1–10 of 235" line, as ONE catalog template.
132
+ *
133
+ * It used to be `` `${start}-${end} ${of} ${total}` ``, which localised the
134
+ * word in the middle and nothing else: the ASCII hyphen between the bounds and
135
+ * the operand order were both frozen in TypeScript, so ja-JP and ar-SA got
136
+ * English word order and no language could change the range separator. The
137
+ * three numbers go through `Intl.NumberFormat` for the same reason the total
138
+ * beside them does — a five-figure total needs the locale's grouping, and
139
+ * ar-SA needs its own digits.
140
+ *
141
+ * The `ofLabel` input is gone with it: an input for the middle word is the
142
+ * concatenation, re-offered as API.
143
+ */
126
144
  protected readonly rangeLabel: _angular_core.Signal<string>;
145
+ /** Internal: the compact pager's `1 / 24`, likewise a catalog template. */
146
+ protected readonly compactLabel: _angular_core.Signal<string>;
147
+ private readonly rangeText;
148
+ private readonly compactText;
149
+ private readonly locale;
150
+ /**
151
+ * Grouped per `LOCALE_ID`. Only the range and the compact pager go through
152
+ * this — a page NUMBER on a button is an identifier, and `1,024` on a button
153
+ * reads as two things.
154
+ */
155
+ private number;
127
156
  /**
128
157
  * Internal: page list with ellipses. Window of 7 visible page slots.
129
158
  *
@@ -142,7 +171,7 @@ declare class WrPagination {
142
171
  constructor();
143
172
  protected onSizeChange(size: unknown): void;
144
173
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrPagination, never>;
145
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrPagination, "wr-pagination", never, { "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "showSizeChanger": { "alias": "showSizeChanger"; "required": false; "isSignal": true; }; "showTotal": { "alias": "showTotal"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "ofLabel": { "alias": "ofLabel"; "required": false; "isSignal": true; }; "prevLabel": { "alias": "prevLabel"; "required": false; "isSignal": true; }; "nextLabel": { "alias": "nextLabel"; "required": false; "isSignal": true; }; "itemsPerPageLabel": { "alias": "itemsPerPageLabel"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, { "currentPage": "currentPageChange"; "pageSize": "pageSizeChange"; }, never, never, true, never>;
174
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrPagination, "wr-pagination", never, { "page": { "alias": "page"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; "total": { "alias": "total"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "showSizeChanger": { "alias": "showSizeChanger"; "required": false; "isSignal": true; }; "showTotal": { "alias": "showTotal"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "shape": { "alias": "shape"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "prevLabel": { "alias": "prevLabel"; "required": false; "isSignal": true; }; "nextLabel": { "alias": "nextLabel"; "required": false; "isSignal": true; }; "itemsPerPageLabel": { "alias": "itemsPerPageLabel"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, { "page": "pageChange"; "pageSize": "pageSizeChange"; }, never, never, true, never>;
146
175
  }
147
176
 
148
177
  export { WrPagination };
@@ -64,7 +64,7 @@ declare class WrPopconfirm {
64
64
  */
65
65
  private isRtl;
66
66
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrPopconfirm, never>;
67
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrPopconfirm, "[wrPopconfirm]", never, { "message": { "alias": "wrPopconfirm"; "required": true; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "confirmText": { "alias": "confirmText"; "required": false; "isSignal": true; }; "cancelText": { "alias": "cancelText"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "confirmColor": { "alias": "confirmColor"; "required": false; "isSignal": true; }; }, { "confirmed": "confirmed"; "cancelled": "cancelled"; }, never, never, true, never>;
67
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrPopconfirm, "[wrPopconfirm]", ["wrPopconfirm"], { "message": { "alias": "wrPopconfirm"; "required": true; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "confirmText": { "alias": "confirmText"; "required": false; "isSignal": true; }; "cancelText": { "alias": "cancelText"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "confirmColor": { "alias": "confirmColor"; "required": false; "isSignal": true; }; }, { "confirmed": "confirmed"; "cancelled": "cancelled"; }, never, never, true, never>;
68
68
  }
69
69
 
70
70
  /**
@@ -111,7 +111,7 @@ declare class WrPopover {
111
111
  */
112
112
  private isRtl;
113
113
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrPopover, never>;
114
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrPopover, "[wrPopover]", never, { "content": { "alias": "wrPopover"; "required": true; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "trigger": { "alias": "trigger"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "showDelay": { "alias": "showDelay"; "required": false; "isSignal": true; }; "hideDelay": { "alias": "hideDelay"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
114
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrPopover, "[wrPopover]", ["wrPopover"], { "content": { "alias": "wrPopover"; "required": true; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "trigger": { "alias": "trigger"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "showDelay": { "alias": "showDelay"; "required": false; "isSignal": true; }; "hideDelay": { "alias": "hideDelay"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "opened": "opened"; "closed": "closed"; }, never, never, true, never>;
115
115
  }
116
116
 
117
117
  export { WrPopover };
@@ -4,8 +4,13 @@ import { FormValueControl } from '@angular/forms/signals';
4
4
 
5
5
  /**
6
6
  * Star rating input. Click or hover to set a value; supports half-star
7
- * increments via `step="0.5"`. Value is `number | null` (clamped to
8
- * `[0, count]`).
7
+ * increments via `step="0.5"`. Value is `number | null`.
8
+ *
9
+ * `[0, count]` bounds what this control's OWN edits produce — a click, an arrow
10
+ * key, `End`. A value written from outside is displayed and announced clamped
11
+ * (a slider cannot report an `aria-valuenow` past its own `aria-valuemax`) and
12
+ * left in the model as it stands, the same rule `wr-slider` and
13
+ * `wr-input-number` follow.
9
14
  *
10
15
  * A signal-forms native control: it implements `FormValueControl<number | null>`,
11
16
  * so `[formField]` binds straight to its `value` model — no
@@ -68,8 +73,25 @@ declare class WrRating implements FormValueControl<number | null> {
68
73
  * an error message on an element nobody could focus.
69
74
  */
70
75
  protected readonly focusable: _angular_core.Signal<boolean>;
71
- /** What we actually render — hover wins while hovering. */
76
+ /**
77
+ * What we actually render — hover wins while hovering.
78
+ *
79
+ * Clamped, because there is no such thing as drawing six stars in a row of
80
+ * five, and the same number is what `aria-valuenow` reports: a `role="slider"`
81
+ * whose value sits outside its own min / max is an invalid slider whatever the
82
+ * model holds. The MODEL is left alone — see the note above `fillFor` for why
83
+ * the clamp is not written back.
84
+ */
72
85
  protected readonly displayValue: _angular_core.Signal<number>;
86
+ /**
87
+ * What the slider REPORTS, and where the arrows start from.
88
+ *
89
+ * Deliberately not `displayValue`: a hover preview is a pointer affordance and
90
+ * must not be announced as the current value, and an arrow press after a hover
91
+ * has to step from the committed number rather than from wherever the mouse
92
+ * happened to rest.
93
+ */
94
+ protected readonly announcedValue: _angular_core.Signal<number>;
73
95
  protected readonly slots: _angular_core.Signal<number[]>;
74
96
  /**
75
97
  * Reading direction, for the two places it changes the answer: the arrows and
@@ -84,7 +106,6 @@ declare class WrRating implements FormValueControl<number | null> {
84
106
  /** The surrounding `<wr-form-field>`'s error state. @internal */
85
107
  protected readonly fieldAria: ngwr_form.WrFormFieldAria;
86
108
  protected readonly classes: _angular_core.Signal<string>;
87
- constructor();
88
109
  /** Fill ratio for slot `i` in `[0, 1]` — drives the CSS clip width. */
89
110
  protected fillFor(i: number): number;
90
111
  protected onSlotMove(event: MouseEvent, index: number): void;
@@ -141,6 +141,7 @@ declare class WrSegmented<T = unknown> implements FormValueControl<T | null> {
141
141
  * because the field only publishes an id once it is showing something — announcing
142
142
  * "invalid" while pointing at nothing is worse than staying quiet.
143
143
  */
144
+ private readonly fieldAria;
144
145
  protected readonly describedBy: _angular_core.Signal<string | null>;
145
146
  protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
146
147
  /** Index of the selected option, or `-1` when nothing is selected. */
@@ -53,10 +53,12 @@ interface WrSelectOptionRegistration {
53
53
  readonly value: unknown;
54
54
  readonly disabled: boolean;
55
55
  /**
56
- * Lazy label reader. Options render text via `<ng-content>`, so we
57
- * read it at call time once Angular has settled the projected content.
56
+ * The option's text, as a signal. Options render it via `<ng-content>`, so it
57
+ * is read back off the DOM — and it has to be reactive, because the ordinary
58
+ * way it changes is a translation catalog landing after the first pass. A
59
+ * plain reader let the trigger cache the English fallback forever.
58
60
  */
59
- readonly getLabel: () => string;
61
+ readonly label: Signal<string>;
60
62
  /**
61
63
  * The option's own element, when it has one. The keyboard cursor walks the
62
64
  * registry, and registration order is CREATION order — projected children are
@@ -104,8 +106,8 @@ interface WrSelectContext {
104
106
  /** Is the given option value currently selected? Handles both single and multi. */
105
107
  isSelected(value: unknown): boolean;
106
108
  /**
107
- * Called when a child option is clicked. The label is read lazily
108
- * via {@link WrSelectOptionRegistration.getLabel}, so callers don't
109
+ * Called when a child option is clicked. The label rides along on the
110
+ * registration ({@link WrSelectOptionRegistration.label}), so callers don't
109
111
  * need to thread it through.
110
112
  */
111
113
  selectOption(value: unknown): void;
@@ -225,15 +227,17 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
225
227
  */
226
228
  protected readonly controlId: _angular_core.Signal<string | null>;
227
229
  /**
228
- * The field's error message, wired to the same element.
230
+ * The field's error message — or, failing that, its hint — wired to the same
231
+ * element, plus the invalid flag.
229
232
  *
230
- * Without it the messages `<wr-form-field>` renders are visible and nothing else:
231
- * a screen reader on the trigger never learns the field is invalid, nor what the
232
- * message says. `aria-invalid` is keyed on the message EXISTING rather than on
233
- * `errorKeys()`, because the field only publishes an id once it is showing
234
- * something — announcing "invalid" while pointing at nothing is worse than
235
- * staying quiet.
236
- */
233
+ * Without it the copy `<wr-form-field>` renders is visible and nothing else: a
234
+ * screen reader on the trigger never learns the field is invalid, nor what the
235
+ * message says. Composed by `useFormFieldAria()` rather than read off the field
236
+ * here, so the trigger picks up the hint the same way the other value controls
237
+ * do and `aria-invalid` stays keyed on the error rather than on "is anything
238
+ * describing me".
239
+ */
240
+ private readonly fieldAria;
237
241
  protected readonly describedBy: _angular_core.Signal<string | null>;
238
242
  protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
239
243
  /**
@@ -510,7 +514,19 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
510
514
  /** Id of the active option (for `aria-activedescendant`). */
511
515
  readonly activeOptionId: _angular_core.Signal<string | null>;
512
516
  protected readonly open: _angular_core.WritableSignal<boolean>;
513
- protected readonly selectedLabel: _angular_core.WritableSignal<string | null>;
517
+ /**
518
+ * Trigger label for single mode. Multi reads `selectedChips` instead.
519
+ *
520
+ * A `computed`, and that is the whole point. It used to be a `signal` written
521
+ * from an effect keyed on `value` / `registry` / `isMulti` / `displayWith` —
522
+ * not one of which moves when the OPTION'S OWN TEXT does, and that text is
523
+ * projected content whose ordinary way of changing is a translation catalog
524
+ * landing a microtask after the first pass. The trigger kept the English
525
+ * fallback while the open panel beside it showed the translation. The
526
+ * registration now carries the label as a signal, so a late catalog and a
527
+ * runtime locale switch both repaint the trigger with the panel.
528
+ */
529
+ protected readonly selectedLabel: _angular_core.Signal<string | null>;
514
530
  /**
515
531
  * Selected chips (multi + tag modes). Multi reads labels from the
516
532
  * registered `<wr-option>` children; tag uses each raw string as
@@ -591,8 +607,41 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
591
607
  protected virtualRowId(i: number): string;
592
608
  /** The virtual scroll container inside the overlay panel, if attached. */
593
609
  private get vlistElement();
594
- /** Scroll filtered index `i` just into view (sets the `scrollTop` signal synchronously). */
610
+ /** The scrolling listbox inside the overlay panel, if attached. */
611
+ private get panelElement();
612
+ /**
613
+ * Scroll the ordered index `i` just into view. Two implementations, because the
614
+ * two panels scroll different elements and know the row geometry in different
615
+ * ways — the virtual list is index maths against a measured row height, the
616
+ * projected list has to read the row it is moving to.
617
+ *
618
+ * The non-virtual half is not an optimisation, it is the whole keyboard
619
+ * contract: `activeIndex` drives `aria-activedescendant`, and NOTHING else
620
+ * moves a projected panel, because the rows never take DOM focus. Without it
621
+ * End on a 250-option `mode="search"` panel announced Zimbabwe while the panel
622
+ * sat at `scrollTop` 0 with the cursor 9 218 px below the fold, and Enter then
623
+ * committed a row the user could not see.
624
+ */
595
625
  private ensureVisible;
626
+ /**
627
+ * Scroll the projected row at ordered index `i` just into view.
628
+ *
629
+ * Geometry is READ rather than computed: projected `<wr-option>` rows are
630
+ * consumer content, so they are not a uniform height the way a virtual row is
631
+ * — a row with a description, an icon or a wrapped label is taller than its
632
+ * neighbours, and index maths would land the panel next to the cursor instead
633
+ * of on it. The offset is taken relative to the panel's own scroll content
634
+ * (`rect.top` difference plus the current `scrollTop`) rather than from
635
+ * `offsetTop`, which is measured against whichever ancestor happens to be
636
+ * positioned.
637
+ *
638
+ * `scrollTop` is written directly instead of `scrollTo`, so the write is
639
+ * observable in a spec — jsdom implements the property and does not implement
640
+ * the method. It still reads as a no-op there, since every jsdom rect is 0×0:
641
+ * a spec asserting a scroll has to stub `getBoundingClientRect` and
642
+ * `clientHeight` on the panel and the row, which `select.spec.ts` does.
643
+ */
644
+ private ensureRowVisible;
596
645
  /**
597
646
  * Count of registered options that pass the current search filter.
598
647
  * Hides the noResults state when the panel has at least one visible row.
@@ -619,6 +668,17 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
619
668
  protected focusSearchInput(): void;
620
669
  protected onChipsInput(event: Event): void;
621
670
  protected onChipsKeydown(event: KeyboardEvent): void;
671
+ /**
672
+ * True when the key belongs to an open IME conversion — and, when it does,
673
+ * stops the event on its way out.
674
+ *
675
+ * Not acting is not enough here. The panel closes on Escape from CDK's overlay
676
+ * keyboard dispatcher, one listener on `<body>` in the bubble phase, so a
677
+ * handler that merely returns still loses the panel: the Japanese user meant
678
+ * to cancel a reading and lost the query with it. Stopping the event at the
679
+ * field that owns the composition is the only place that reaches both.
680
+ */
681
+ private imeOwnsKey;
622
682
  protected onChipsFocus(): void;
623
683
  protected onChipsPaste(event: ClipboardEvent): void;
624
684
  protected onChipsBlur(): void;
@@ -649,6 +709,7 @@ declare class WrSelect implements FormValueControl<unknown>, WrSelectContext {
649
709
  private readonly scrollStrategies;
650
710
  private readonly destroyRef;
651
711
  private readonly platformId;
712
+ private readonly injector;
652
713
  private overlayRef;
653
714
  constructor();
654
715
  isSelected(value: unknown): boolean;
@@ -724,22 +785,52 @@ declare class WrOption {
724
785
  readonly id: string;
725
786
  private readonly host;
726
787
  private readonly parent;
788
+ /**
789
+ * The option's own text, as a signal — the parent's trigger label and the
790
+ * client-side filter both read it from here.
791
+ *
792
+ * It has to be a signal, and a plain `textContent` read cannot be one. The
793
+ * label is PROJECTED content: the host template decides it, and the ordinary
794
+ * way it changes is that a `WrI18n` catalog lands a microtask after the first
795
+ * change-detection pass (`i18n/i18n.ts` writes every loader-backed catalog
796
+ * from `firstValueFrom(...).then(...)`). Read once and cached, a trigger sat
797
+ * on the English fallback while the open panel beside it showed the
798
+ * translation — visible in `wr-pagination`'s size changer, which prints
799
+ * `pagination.perPage` into each `<wr-option>`.
800
+ *
801
+ * Kept in step the way `wr-divider` keeps its own projected label: an
802
+ * `effect` and an `afterEveryRender`, and both are needed. The render hook is
803
+ * a hard no-op under SSR, so on its own the server would emit a trigger with
804
+ * no label at all; the effect is not gated that way and runs after the
805
+ * content has been projected. The effect on its own cannot follow text that
806
+ * moves later, because it reads nothing reactive to be re-run by.
807
+ *
808
+ * @internal
809
+ */
810
+ private readonly labelText;
811
+ private readonly label;
727
812
  /**
728
813
  * @internal — true when this option is currently selected. Works for
729
814
  * both single and multi-select parents via `WrSelectContext.isSelected`.
730
815
  */
731
- protected readonly selected: _angular_core.Signal<boolean>;
816
+ protected readonly selected: Signal<boolean>;
732
817
  /** @internal — true when this option is the keyboard cursor target. */
733
- protected readonly active: _angular_core.Signal<boolean>;
818
+ protected readonly active: Signal<boolean>;
734
819
  /**
735
820
  * @internal — searchable selects only. True when the parent has a query that
736
821
  * the option's text content does not match (case-insensitive substring).
737
822
  * Hidden options stay in the DOM so registration order survives but
738
823
  * collapse via CSS.
739
824
  */
740
- protected readonly hidden: _angular_core.Signal<boolean>;
741
- protected readonly classes: _angular_core.Signal<string>;
825
+ protected readonly hidden: Signal<boolean>;
826
+ protected readonly classes: Signal<string>;
742
827
  constructor();
828
+ /**
829
+ * Read the projected text back off the DOM. Setting the same string again is
830
+ * a signal no-op, so the render hook costs a `textContent` read and nothing
831
+ * else on the passes where nothing moved.
832
+ */
833
+ private syncLabel;
743
834
  protected onClick(): void;
744
835
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrOption, never>;
745
836
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrOption, "wr-option", never, { "value": { "alias": "value"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
@@ -137,6 +137,7 @@ declare class WrSlider implements FormValueControl<WrSliderValue> {
137
137
  * showing something — announcing "invalid" while pointing at nothing is worse
138
138
  * than staying quiet.
139
139
  */
140
+ private readonly fieldAria;
140
141
  protected readonly describedBy: _angular_core.Signal<string | null>;
141
142
  protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
142
143
  /**
@@ -7,6 +7,13 @@ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular
7
7
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
8
  */
9
9
 
10
+ /**
11
+ * An arrow key, by the direction a user would say out loud — the parameter type
12
+ * of `WrSplitterHarness.pressArrow`, exported so a consumer's own test helper can
13
+ * name what it forwards. Arrows follow the VISUAL axis, so `left` shrinks the
14
+ * position in LTR and grows it in RTL.
15
+ */
16
+ type WrSplitterArrowKey = 'left' | 'right' | 'up' | 'down';
10
17
  /** Narrows which `<wr-splitter>` a harness query matches. */
11
18
  interface WrSplitterHarnessFilters extends BaseHarnessFilters {
12
19
  /**
@@ -35,8 +42,6 @@ interface WrSplitterPaneSizes {
35
42
  * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
36
43
  */
37
44
 
38
- /** The four arrow keys, by the direction a user would say out loud. */
39
- type Arrow = 'left' | 'right' | 'up' | 'down';
40
45
  /**
41
46
  * Test harness for `<wr-splitter>` — two panes and the divider between them.
42
47
  *
@@ -135,7 +140,7 @@ declare class WrSplitterHarness extends ComponentHarness {
135
140
  *
136
141
  * `shift` is the coarse step: 10 instead of 1.
137
142
  */
138
- pressArrow(arrow: Arrow, options?: {
143
+ pressArrow(arrow: WrSplitterArrowKey, options?: {
139
144
  shift?: boolean;
140
145
  }): Promise<void>;
141
146
  /** Press Home — jumping to `minPosition`, whatever the reading direction. */
@@ -171,4 +176,4 @@ declare class WrSplitterHarness extends ComponentHarness {
171
176
  }
172
177
 
173
178
  export { WrSplitterHarness };
174
- export type { WrSplitterHarnessFilters, WrSplitterPaneSizes };
179
+ export type { WrSplitterArrowKey, WrSplitterHarnessFilters, WrSplitterPaneSizes };
@@ -107,7 +107,7 @@ declare class WrSquircle {
107
107
  private apply;
108
108
  private clear;
109
109
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrSquircle, never>;
110
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrSquircle, "[wrSquircle]", never, { "radius": { "alias": "radius"; "required": false; "isSignal": true; }; "smoothing": { "alias": "smoothing"; "required": false; "isSignal": true; }; "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "borderWidth": { "alias": "borderWidth"; "required": false; "isSignal": true; }; "borderColor": { "alias": "borderColor"; "required": false; "isSignal": true; }; "corners": { "alias": "corners"; "required": false; "isSignal": true; }; }, { "enabled": "enabledChange"; "borderWidth": "borderWidthChange"; "borderColor": "borderColorChange"; "corners": "cornersChange"; }, never, never, true, never>;
110
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<WrSquircle, "[wrSquircle]", ["wrSquircle"], { "radius": { "alias": "radius"; "required": false; "isSignal": true; }; "smoothing": { "alias": "smoothing"; "required": false; "isSignal": true; }; "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "borderWidth": { "alias": "borderWidth"; "required": false; "isSignal": true; }; "borderColor": { "alias": "borderColor"; "required": false; "isSignal": true; }; "corners": { "alias": "corners"; "required": false; "isSignal": true; }; }, { "enabled": "enabledChange"; "borderWidth": "borderWidthChange"; "borderColor": "borderColorChange"; "corners": "cornersChange"; }, never, never, true, never>;
111
111
  }
112
112
 
113
113
  /**
@@ -59,10 +59,30 @@ declare class WrStatistic {
59
59
  * Use `deltaSuffix` to change the trailing unit.
60
60
  */
61
61
  readonly delta: _angular_core.InputSignalWithTransform<number | null, unknown>;
62
- /** Unit appended to the delta value. @default '%' */
63
- readonly deltaSuffix: _angular_core.InputSignal<string>;
62
+ /** Unit appended to the delta value. Falls back to `statistic.deltaSuffix`, then `'%'`. */
63
+ readonly deltaSuffix: _angular_core.InputSignal<string | null>;
64
64
  protected readonly hasDelta: _angular_core.Signal<boolean>;
65
65
  protected readonly deltaDirection: _angular_core.Signal<"up" | "down" | "flat">;
66
+ protected readonly resolvedDeltaSuffix: _angular_core.Signal<string>;
67
+ /** `{{value}}{{suffix}}` — the join, so a locale owns the space before the unit. */
68
+ private readonly deltaFormat;
69
+ /**
70
+ * The delta chip, e.g. `+12.4%`.
71
+ *
72
+ * It was `` `${sign}${d}${suffix}` ``, printed one line under a value that
73
+ * goes through `Intl.NumberFormat` — so the two disagreed inside one
74
+ * component: ar-SA showed `١٬٢٣٤٬٥٦٧٫٨٩` above a Latin `12.4%`, and de-DE
75
+ * `1.234.567,89` above `+12.4%`. The sign comes from `signDisplay`, which also
76
+ * fixes the RTL half of it: `+` written by hand is a neutral character that
77
+ * the BiDi algorithm moves to the other end of the number.
78
+ *
79
+ * The digit count is taken from the number rather than from `precision()`,
80
+ * which describes the VALUE and not the delta — so what renders is the same
81
+ * digits as before, in the locale's own numerals. One exception, and it is an
82
+ * improvement rather than a regression: a magnitude JavaScript prints in
83
+ * exponent notation (`1e-7`, `1e+21`) used to reach the DOM that way and is
84
+ * now formatted as a number.
85
+ */
66
86
  protected readonly deltaText: _angular_core.Signal<string>;
67
87
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrStatistic, never>;
68
88
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrStatistic, "wr-statistic", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "prefix": { "alias": "prefix"; "required": false; "isSignal": true; }; "suffix": { "alias": "suffix"; "required": false; "isSignal": true; }; "precision": { "alias": "precision"; "required": false; "isSignal": true; }; "animate": { "alias": "animate"; "required": false; "isSignal": true; }; "duration": { "alias": "duration"; "required": false; "isSignal": true; }; "delta": { "alias": "delta"; "required": false; "isSignal": true; }; "deltaSuffix": { "alias": "deltaSuffix"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -14,6 +14,9 @@ import * as ngwr_storage from 'ngwr/storage';
14
14
  * lazily on the next `get` / `watch` read.
15
15
  * - **Reactive watch** — `watch(key)` returns a `Signal` that updates on
16
16
  * local writes and cross-tab `storage` events.
17
+ * - **On-disk format** — values are wrapped in a {@link WrStorageEnvelope}
18
+ * (`{"v":…,"e":…}`) while `json` is on. Anything reading the same key from
19
+ * outside Angular has to unwrap it.
17
20
  *
18
21
  * SSR-safe: the default engine factory returns an in-memory shim when
19
22
  * `localStorage` is unavailable, so reads always work.
@@ -60,6 +63,11 @@ declare class WrStorage {
60
63
  /**
61
64
  * Write `value` at `key`. Per-call `ttl` (ms) overrides the config
62
65
  * default. JSON-serializable values only when `json` is on (the default).
66
+ *
67
+ * What lands in the engine is a {@link WrStorageEnvelope} —
68
+ * `{"v":<value>}`, plus `"e"` when a TTL applies — not the bare value. Code
69
+ * outside Angular that reads the same key has to unwrap it; see the envelope's
70
+ * own docs for the exact format.
63
71
  */
64
72
  set<T = unknown>(key: string, value: T, opts?: {
65
73
  ttl?: number;
@@ -118,6 +126,36 @@ interface WrStorageConfig {
118
126
  }
119
127
  /** Fully-resolved config (all defaults filled). @internal */
120
128
  type WrStorageConfigResolved = Required<WrStorageConfig>;
129
+ /**
130
+ * The **on-disk format** `WrStorage` writes while `json` is on (the default).
131
+ *
132
+ * Public because it is a wire format, not an implementation detail: the value in
133
+ * `localStorage` is `JSON.stringify(envelope)`, so anything reading the same key
134
+ * from outside Angular — a pre-paint theme script in `index.html`, a service
135
+ * worker, a native shell, another framework on the same origin — has to know
136
+ * that a stored `'dark'` is spelled `{"v":"dark"}` and not `"dark"`. Left
137
+ * undocumented, the only way to learn that was to read the bundle.
138
+ *
139
+ * `e` is an absolute expiry in epoch milliseconds, written only when a TTL
140
+ * applies; a value past it reads as absent and is removed on the next `get`.
141
+ * A key holding anything else — a bare JSON value, or a string that is not JSON
142
+ * at all — is returned as it stands, so keys written by non-ngwr code keep
143
+ * working.
144
+ *
145
+ * @example
146
+ * ```jsonc
147
+ * // localStorage['wr-theme']
148
+ * { "v": "dark" }
149
+ * // localStorage['cart'], written with { ttl: 60_000 }
150
+ * { "v": [{ "sku": "a1" }], "e": 1767225600000 }
151
+ * ```
152
+ */
153
+ interface WrStorageEnvelope<T = unknown> {
154
+ /** The stored value, as handed to `set()`. */
155
+ readonly v: T;
156
+ /** Absolute expiry, epoch ms. Absent when the write carried no TTL. */
157
+ readonly e?: number;
158
+ }
121
159
 
122
160
  declare const DEFAULT_WR_STORAGE_CONFIG: WrStorageConfigResolved;
123
161
  declare const WR_STORAGE_CONFIG: InjectionToken<Required<ngwr_storage.WrStorageConfig>>;
@@ -185,4 +223,4 @@ interface ProvideWrStorageOptions extends WrStorageConfig {
185
223
  declare function provideWrStorage(options?: ProvideWrStorageOptions): EnvironmentProviders;
186
224
 
187
225
  export { DEFAULT_WR_STORAGE_CONFIG, WR_STORAGE_CONFIG, WR_STORAGE_ENGINE, WrStorage, createMemoryStorage, provideWrStorage };
188
- export type { ProvideWrStorageOptions, WrStorageConfig, WrStorageConfigResolved, WrStorageEngine };
226
+ export type { ProvideWrStorageOptions, WrStorageConfig, WrStorageConfigResolved, WrStorageEngine, WrStorageEnvelope };