ngwr 11.0.0 → 11.2.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 (237) hide show
  1. package/action-sheet/styles/_index.scss +4 -1
  2. package/anchor/styles/_index.scss +2 -1
  3. package/calendar/styles/_index.scss +11 -2
  4. package/cascader/styles/_index.scss +3 -1
  5. package/circular-text/styles/_index.scss +11 -0
  6. package/command-palette/styles/_index.scss +14 -1
  7. package/context-menu/styles/_index.scss +2 -1
  8. package/falling-text/styles/_index.scss +2 -1
  9. package/fesm2022/ngwr-action-sheet-testing.mjs +313 -0
  10. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -0
  11. package/fesm2022/ngwr-bar-chart-testing.mjs +89 -0
  12. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -0
  13. package/fesm2022/ngwr-blur-text-testing.mjs +203 -0
  14. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -0
  15. package/fesm2022/ngwr-blur-text.mjs +15 -1
  16. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  17. package/fesm2022/ngwr-border-glow-testing.mjs +325 -0
  18. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -0
  19. package/fesm2022/ngwr-border-glow.mjs +2 -2
  20. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  21. package/fesm2022/ngwr-calendar-heatmap-testing.mjs +95 -0
  22. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -0
  23. package/fesm2022/ngwr-calendar-testing.mjs +368 -0
  24. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -0
  25. package/fesm2022/ngwr-calendar.mjs +43 -3
  26. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  27. package/fesm2022/ngwr-card.mjs +2 -2
  28. package/fesm2022/ngwr-cascader.mjs +14 -2
  29. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  30. package/fesm2022/ngwr-checkbox.mjs +8 -0
  31. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  32. package/fesm2022/ngwr-circular-text-testing.mjs +230 -0
  33. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -0
  34. package/fesm2022/ngwr-circular-text.mjs +2 -2
  35. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  36. package/fesm2022/ngwr-color-picker-testing.mjs +432 -0
  37. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -0
  38. package/fesm2022/ngwr-color-picker.mjs +29 -3
  39. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  40. package/fesm2022/ngwr-context-menu.mjs +25 -5
  41. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  42. package/fesm2022/ngwr-date-picker-testing.mjs +10 -79
  43. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  44. package/fesm2022/ngwr-decrypt-text-testing.mjs +261 -0
  45. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -0
  46. package/fesm2022/ngwr-decrypt-text.mjs +6 -1
  47. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  48. package/fesm2022/ngwr-donut-chart-testing.mjs +93 -0
  49. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -0
  50. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  51. package/fesm2022/ngwr-drawer.mjs +36 -7
  52. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  53. package/fesm2022/ngwr-dropdown.mjs +32 -2
  54. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  55. package/fesm2022/ngwr-event-calendar-testing.mjs +446 -0
  56. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -0
  57. package/fesm2022/ngwr-event-calendar.mjs +43 -18
  58. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  59. package/fesm2022/ngwr-falling-text-testing.mjs +218 -0
  60. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -0
  61. package/fesm2022/ngwr-falling-text.mjs +2 -2
  62. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  63. package/fesm2022/ngwr-fuzzy-text-testing.mjs +134 -0
  64. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -0
  65. package/fesm2022/ngwr-gauge-testing.mjs +86 -0
  66. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -0
  67. package/fesm2022/ngwr-glitch-text-testing.mjs +181 -0
  68. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -0
  69. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  70. package/fesm2022/ngwr-gradient-text-testing.mjs +223 -0
  71. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -0
  72. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  73. package/fesm2022/ngwr-i18n-en.mjs +14 -0
  74. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  75. package/fesm2022/ngwr-i18n-ru.mjs +14 -0
  76. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  77. package/fesm2022/ngwr-image-cropper-testing.mjs +156 -0
  78. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -0
  79. package/fesm2022/ngwr-image-cropper.mjs +10 -3
  80. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  81. package/fesm2022/ngwr-input-number.mjs +73 -6
  82. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  83. package/fesm2022/ngwr-knob-testing.mjs +220 -0
  84. package/fesm2022/ngwr-knob-testing.mjs.map +1 -0
  85. package/fesm2022/ngwr-lightbox-testing.mjs +223 -0
  86. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -0
  87. package/fesm2022/ngwr-lightbox.mjs +9 -2
  88. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  89. package/fesm2022/ngwr-line-chart-testing.mjs +119 -0
  90. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -0
  91. package/fesm2022/ngwr-list.mjs +2 -2
  92. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  93. package/fesm2022/ngwr-marquee-testing.mjs +336 -0
  94. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -0
  95. package/fesm2022/ngwr-marquee.mjs +2 -2
  96. package/fesm2022/ngwr-meter-group-testing.mjs +80 -0
  97. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -0
  98. package/fesm2022/ngwr-overlay.mjs +28 -1
  99. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  100. package/fesm2022/ngwr-popover.mjs +14 -0
  101. package/fesm2022/ngwr-popover.mjs.map +1 -1
  102. package/fesm2022/ngwr-rotating-text-testing.mjs +220 -0
  103. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -0
  104. package/fesm2022/ngwr-rotating-text.mjs +2 -2
  105. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  106. package/fesm2022/ngwr-select.mjs +70 -11
  107. package/fesm2022/ngwr-select.mjs.map +1 -1
  108. package/fesm2022/ngwr-shiny-text-testing.mjs +237 -0
  109. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -0
  110. package/fesm2022/ngwr-shiny-text.mjs +2 -2
  111. package/fesm2022/ngwr-slider.mjs +44 -6
  112. package/fesm2022/ngwr-slider.mjs.map +1 -1
  113. package/fesm2022/ngwr-sparkline-testing.mjs +76 -0
  114. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -0
  115. package/fesm2022/ngwr-speed-dial-testing.mjs +279 -0
  116. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -0
  117. package/fesm2022/ngwr-splash-cursor-testing.mjs +89 -0
  118. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -0
  119. package/fesm2022/ngwr-split-text-testing.mjs +224 -0
  120. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -0
  121. package/fesm2022/ngwr-split-text.mjs +15 -1
  122. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  123. package/fesm2022/ngwr-splitter-testing.mjs +245 -0
  124. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -0
  125. package/fesm2022/ngwr-spotlight-card-testing.mjs +368 -0
  126. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -0
  127. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  128. package/fesm2022/ngwr-star-border-testing.mjs +172 -0
  129. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -0
  130. package/fesm2022/ngwr-star-border.mjs +2 -2
  131. package/fesm2022/ngwr-table.mjs +13 -3
  132. package/fesm2022/ngwr-table.mjs.map +1 -1
  133. package/fesm2022/ngwr-tabs.mjs +15 -1
  134. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  135. package/fesm2022/ngwr-tilt-card-testing.mjs +190 -0
  136. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -0
  137. package/fesm2022/ngwr-tilt-card.mjs +21 -3
  138. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  139. package/fesm2022/ngwr-toast.mjs +36 -7
  140. package/fesm2022/ngwr-toast.mjs.map +1 -1
  141. package/fesm2022/ngwr-tour-testing.mjs +173 -0
  142. package/fesm2022/ngwr-tour-testing.mjs.map +1 -0
  143. package/fesm2022/ngwr-tour.mjs +2 -2
  144. package/fesm2022/ngwr-tour.mjs.map +1 -1
  145. package/fesm2022/ngwr-tree.mjs +10 -3
  146. package/fesm2022/ngwr-tree.mjs.map +1 -1
  147. package/fesm2022/ngwr-typewriter-testing.mjs +228 -0
  148. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -0
  149. package/fesm2022/ngwr-typewriter.mjs +2 -2
  150. package/fesm2022/ngwr-version.mjs +1 -1
  151. package/fesm2022/ngwr-version.mjs.map +1 -1
  152. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  153. package/fesm2022/ngwr-waves-testing.mjs +128 -0
  154. package/fesm2022/ngwr-waves-testing.mjs.map +1 -0
  155. package/fesm2022/ngwr-waves.mjs +2 -2
  156. package/fesm2022/ngwr-window-testing.mjs +361 -0
  157. package/fesm2022/ngwr-window-testing.mjs.map +1 -0
  158. package/fesm2022/ngwr-window.mjs +84 -10
  159. package/fesm2022/ngwr-window.mjs.map +1 -1
  160. package/file-upload/styles/_index.scss +7 -2
  161. package/i18n/en.json +16 -2
  162. package/i18n/ru.json +16 -2
  163. package/llms-full.txt +147 -0
  164. package/llms.txt +27 -8
  165. package/mcp/providers.js +29 -0
  166. package/mcp/tools.js +1 -29
  167. package/package.json +145 -1
  168. package/result/styles/_index.scss +3 -1
  169. package/segmented/styles/_index.scss +5 -1
  170. package/select/styles/_index.scss +3 -1
  171. package/skills/ngwr/SKILL.md +115 -0
  172. package/skills/ngwr/references/catalog.md +212 -0
  173. package/skills/ngwr/references/setup.md +73 -0
  174. package/stepper/styles/_index.scss +18 -2
  175. package/table/styles/_index.scss +3 -1
  176. package/theme/styles/_colors.scss +15 -2
  177. package/theme/styles/_dark.scss +24 -12
  178. package/tree/styles/_index.scss +4 -2
  179. package/types/ngwr-action-sheet-testing.d.ts +260 -0
  180. package/types/ngwr-bar-chart-testing.d.ts +77 -0
  181. package/types/ngwr-blur-text-testing.d.ts +180 -0
  182. package/types/ngwr-blur-text.d.ts +12 -0
  183. package/types/ngwr-border-glow-testing.d.ts +219 -0
  184. package/types/ngwr-calendar-heatmap-testing.d.ts +79 -0
  185. package/types/ngwr-calendar-testing.d.ts +277 -0
  186. package/types/ngwr-calendar.d.ts +10 -0
  187. package/types/ngwr-checkbox.d.ts +13 -0
  188. package/types/ngwr-circular-text-testing.d.ts +196 -0
  189. package/types/ngwr-color-picker-testing.d.ts +291 -0
  190. package/types/ngwr-color-picker.d.ts +13 -1
  191. package/types/ngwr-context-menu.d.ts +15 -1
  192. package/types/ngwr-date-picker-testing.d.ts +6 -66
  193. package/types/ngwr-decrypt-text-testing.d.ts +222 -0
  194. package/types/ngwr-donut-chart-testing.d.ts +79 -0
  195. package/types/ngwr-drawer.d.ts +12 -0
  196. package/types/ngwr-dropdown.d.ts +9 -0
  197. package/types/ngwr-event-calendar-testing.d.ts +301 -0
  198. package/types/ngwr-event-calendar.d.ts +9 -6
  199. package/types/ngwr-falling-text-testing.d.ts +186 -0
  200. package/types/ngwr-fuzzy-text-testing.d.ts +130 -0
  201. package/types/ngwr-gauge-testing.d.ts +71 -0
  202. package/types/ngwr-glitch-text-testing.d.ts +172 -0
  203. package/types/ngwr-gradient-text-testing.d.ts +173 -0
  204. package/types/ngwr-image-cropper-testing.d.ts +134 -0
  205. package/types/ngwr-image-cropper.d.ts +1 -0
  206. package/types/ngwr-input-number.d.ts +33 -1
  207. package/types/ngwr-knob-testing.d.ts +150 -0
  208. package/types/ngwr-lightbox-testing.d.ts +154 -0
  209. package/types/ngwr-lightbox.d.ts +6 -0
  210. package/types/ngwr-line-chart-testing.d.ts +93 -0
  211. package/types/ngwr-marquee-testing.d.ts +280 -0
  212. package/types/ngwr-meter-group-testing.d.ts +67 -0
  213. package/types/ngwr-overlay.d.ts +19 -1
  214. package/types/ngwr-rotating-text-testing.d.ts +191 -0
  215. package/types/ngwr-select.d.ts +32 -0
  216. package/types/ngwr-shiny-text-testing.d.ts +165 -0
  217. package/types/ngwr-slider.d.ts +15 -0
  218. package/types/ngwr-sparkline-testing.d.ts +69 -0
  219. package/types/ngwr-speed-dial-testing.d.ts +195 -0
  220. package/types/ngwr-splash-cursor-testing.d.ts +95 -0
  221. package/types/ngwr-split-text-testing.d.ts +209 -0
  222. package/types/ngwr-split-text.d.ts +12 -0
  223. package/types/ngwr-splitter-testing.d.ts +174 -0
  224. package/types/ngwr-spotlight-card-testing.d.ts +303 -0
  225. package/types/ngwr-star-border-testing.d.ts +135 -0
  226. package/types/ngwr-table.d.ts +10 -1
  227. package/types/ngwr-tilt-card-testing.d.ts +158 -0
  228. package/types/ngwr-tilt-card.d.ts +2 -0
  229. package/types/ngwr-toast.d.ts +14 -5
  230. package/types/ngwr-tour-testing.d.ts +143 -0
  231. package/types/ngwr-tree.d.ts +7 -0
  232. package/types/ngwr-typewriter-testing.d.ts +201 -0
  233. package/types/ngwr-version.d.ts +1 -1
  234. package/types/ngwr-waves-testing.d.ts +121 -0
  235. package/types/ngwr-window-testing.d.ts +263 -0
  236. package/types/ngwr-window.d.ts +27 -10
  237. package/window/styles/_index.scss +44 -16
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-tilt-card.mjs","sources":["../../../projects/lib/tilt-card/tilt.ts","../../../projects/lib/tilt-card/tilt-card.ts","../../../projects/lib/tilt-card/ngwr-tilt-card.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Directive, ElementRef, NgZone, PLATFORM_ID, effect, inject, input } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\n\n/**\n * 3D mouse-tilt on hover. Adds `perspective(…) rotateX(…) rotateY(…)` to\n * the host's transform tracking the cursor's position over it.\n *\n * @example\n * ```html\n * <div class=\"card\" wrTilt>…</div>\n * <div class=\"card\" wrTilt maxTilt=\"20\" [glare]=\"true\">…</div>\n * ```\n */\n@Directive({\n selector: '[wrTilt]',\n host: { '(pointermove)': 'onMove($event)', '(pointerleave)': 'onLeave()' },\n})\nexport class WrTilt {\n /** Maximum tilt in degrees. @default 12 */\n readonly maxTilt = input(12, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 12)) });\n\n /** CSS perspective in pixels. @default 800 */\n readonly perspective = input(800, {\n transform: (v: unknown): number => Math.max(100, coerceNumberProperty(v, 800)),\n });\n\n /** Scale applied while hovered. @default 1.03 */\n readonly scale = input(1.03, { transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 1.03)) });\n\n /** Add a moving glare highlight overlay. @default false */\n readonly glare = input(false, { transform: coerceBooleanProperty });\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly zone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private glareEl: HTMLElement | null = null;\n\n constructor() {\n const host = this.el.nativeElement;\n host.style.transformStyle = 'preserve-3d';\n host.style.transition = 'transform 0.15s ease-out';\n\n // Signal inputs are not bound yet while the constructor runs, so reading\n // `glare()` here would always see the default and the overlay would never\n // appear. Track it instead, so toggling the input at runtime works too.\n // Only in the browser: `installGlare` measures with `getComputedStyle`,\n // and the server has no layout to measure.\n if (this.isBrowser) {\n effect(() => (this.glare() ? this.installGlare() : this.removeGlare()));\n }\n\n this.destroyRef.onDestroy(() => {\n host.style.transform = '';\n this.removeGlare();\n });\n }\n\n /** @internal */\n protected onMove(event: PointerEvent): void {\n // Reduced motion: no pointer-tracking tilt — the card stays flat.\n if (this.platform.prefersReducedMotion()) return;\n this.zone.runOutsideAngular(() => {\n const host = this.el.nativeElement;\n const rect = host.getBoundingClientRect();\n const px = (event.clientX - rect.left) / rect.width;\n const py = (event.clientY - rect.top) / rect.height;\n const rx = (0.5 - py) * this.maxTilt();\n const ry = (px - 0.5) * this.maxTilt();\n host.style.transform = `perspective(${this.perspective()}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${this.scale()})`;\n if (this.glare()) {\n host.style.setProperty('--wr-tilt-glare-x', `${px * 100}%`);\n host.style.setProperty('--wr-tilt-glare-y', `${py * 100}%`);\n }\n });\n }\n\n /** @internal */\n protected onLeave(): void {\n this.el.nativeElement.style.transform = '';\n }\n\n private installGlare(): void {\n if (this.glareEl) return;\n const host = this.el.nativeElement;\n if (getComputedStyle(host).position === 'static') host.style.position = 'relative';\n host.style.overflow = 'hidden';\n const glare = host.ownerDocument.createElement('span');\n glare.className = 'wr-tilt-glare';\n glare.setAttribute('aria-hidden', 'true');\n host.appendChild(glare);\n this.glareEl = glare;\n }\n\n private removeGlare(): void {\n this.glareEl?.remove();\n this.glareEl = null;\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation } from '@angular/core';\n\nimport { WrTilt } from './tilt';\n\n/**\n * Card wrapper that applies the `[wrTilt]` directive out-of-the-box,\n * plus a small set of card-style defaults (radius, padding, surface).\n * Pass any inputs through — they're forwarded to the hosted directive.\n *\n * For arbitrary elements that just need the tilt behaviour, use the\n * `[wrTilt]` directive directly:\n *\n * ```html\n * <img wrTilt [maxTilt]=\"10\" src=\"…\" />\n * ```\n *\n * @example\n * ```html\n * <wr-tilt-card>\n * <h3>Hello</h3>\n * <p>Move the cursor across me.</p>\n * </wr-tilt-card>\n *\n * <wr-tilt-card [maxTilt]=\"20\" [glare]=\"true\">…</wr-tilt-card>\n * ```\n */\n@Component({\n selector: 'wr-tilt-card',\n template: '<ng-content />',\n styleUrl: './tilt-card.scss',\n encapsulation: ViewEncapsulation.None,\n hostDirectives: [\n {\n directive: WrTilt,\n inputs: ['maxTilt', 'perspective', 'scale', 'glare'],\n },\n ],\n host: { class: 'wr-tilt-card' },\n})\nexport class WrTiltCard {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-tilt-card.mjs","sources":["../../../projects/lib/tilt-card/tilt.ts","../../../projects/lib/tilt-card/tilt-card.ts","../../../projects/lib/tilt-card/ngwr-tilt-card.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, Directive, ElementRef, NgZone, PLATFORM_ID, effect, inject, input } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\n\n/**\n * 3D mouse-tilt on hover. Adds `perspective(…) rotateX(…) rotateY(…)` to\n * the host's transform tracking the cursor's position over it.\n *\n * @example\n * ```html\n * <div class=\"card\" wrTilt>…</div>\n * <div class=\"card\" wrTilt maxTilt=\"20\" [glare]=\"true\">…</div>\n * ```\n */\n@Directive({\n selector: '[wrTilt]',\n host: { '(pointermove)': 'onMove($event)', '(pointerleave)': 'onLeave()' },\n})\nexport class WrTilt {\n /** Maximum tilt in degrees. @default 12 */\n readonly maxTilt = input(12, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 12)) });\n\n /** CSS perspective in pixels. @default 800 */\n readonly perspective = input(800, {\n transform: (v: unknown): number => Math.max(100, coerceNumberProperty(v, 800)),\n });\n\n /** Scale applied while hovered. @default 1.03 */\n readonly scale = input(1.03, { transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 1.03)) });\n\n /** Add a moving glare highlight overlay. @default false */\n readonly glare = input(false, { transform: coerceBooleanProperty });\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly zone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private glareEl: HTMLElement | null = null;\n private priorOverflow = '';\n private priorPosition = '';\n\n constructor() {\n const host = this.el.nativeElement;\n host.style.transformStyle = 'preserve-3d';\n host.style.transition = 'transform 0.15s ease-out';\n\n // Signal inputs are not bound yet while the constructor runs, so reading\n // `glare()` here would always see the default and the overlay would never\n // appear. Track it instead, so toggling the input at runtime works too.\n // Only in the browser: `installGlare` measures with `getComputedStyle`,\n // and the server has no layout to measure.\n if (this.isBrowser) {\n effect(() => (this.glare() ? this.installGlare() : this.removeGlare()));\n }\n\n this.destroyRef.onDestroy(() => {\n host.style.transform = '';\n this.removeGlare();\n });\n }\n\n /** @internal */\n protected onMove(event: PointerEvent): void {\n // Reduced motion: no pointer-tracking tilt — the card stays flat.\n if (this.platform.prefersReducedMotion()) return;\n this.zone.runOutsideAngular(() => {\n const host = this.el.nativeElement;\n const rect = host.getBoundingClientRect();\n const px = (event.clientX - rect.left) / rect.width;\n const py = (event.clientY - rect.top) / rect.height;\n const rx = (0.5 - py) * this.maxTilt();\n const ry = (px - 0.5) * this.maxTilt();\n host.style.transform = `perspective(${this.perspective()}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${this.scale()})`;\n if (this.glare()) {\n host.style.setProperty('--wr-tilt-glare-x', `${px * 100}%`);\n host.style.setProperty('--wr-tilt-glare-y', `${py * 100}%`);\n }\n });\n }\n\n /** @internal */\n protected onLeave(): void {\n this.el.nativeElement.style.transform = '';\n }\n\n private installGlare(): void {\n if (this.glareEl) return;\n const host = this.el.nativeElement;\n\n // Remembered, not assumed: `overflow` is written unconditionally, so it can be\n // clobbering an author's own inline value, and a blanket `removeProperty` on the\n // way out would delete it. Capturing the empty string is exactly what restores an\n // element that had none — which is the common case, and the one that used to keep\n // `overflow: hidden` for good after `[glare]` was turned back off.\n this.priorOverflow = host.style.overflow;\n this.priorPosition = host.style.position;\n\n if (getComputedStyle(host).position === 'static') host.style.position = 'relative';\n host.style.overflow = 'hidden';\n const glare = host.ownerDocument.createElement('span');\n glare.className = 'wr-tilt-glare';\n glare.setAttribute('aria-hidden', 'true');\n host.appendChild(glare);\n this.glareEl = glare;\n }\n\n private removeGlare(): void {\n if (!this.glareEl) return;\n\n const host = this.el.nativeElement;\n this.glareEl.remove();\n this.glareEl = null;\n host.style.overflow = this.priorOverflow;\n host.style.position = this.priorPosition;\n // Nothing reads these once the overlay is gone; leaving them behind only makes a\n // destroyed directive look like it is still tracking a pointer.\n host.style.removeProperty('--wr-tilt-glare-x');\n host.style.removeProperty('--wr-tilt-glare-y');\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation } from '@angular/core';\n\nimport { WrTilt } from './tilt';\n\n/**\n * Card wrapper that applies the `[wrTilt]` directive out-of-the-box,\n * plus a small set of card-style defaults (radius, padding, surface).\n * Pass any inputs through — they're forwarded to the hosted directive.\n *\n * For arbitrary elements that just need the tilt behaviour, use the\n * `[wrTilt]` directive directly:\n *\n * ```html\n * <img wrTilt [maxTilt]=\"10\" src=\"…\" />\n * ```\n *\n * @example\n * ```html\n * <wr-tilt-card>\n * <h3>Hello</h3>\n * <p>Move the cursor across me.</p>\n * </wr-tilt-card>\n *\n * <wr-tilt-card [maxTilt]=\"20\" [glare]=\"true\">…</wr-tilt-card>\n * ```\n */\n@Component({\n selector: 'wr-tilt-card',\n template: '<ng-content />',\n styleUrl: './tilt-card.scss',\n encapsulation: ViewEncapsulation.None,\n hostDirectives: [\n {\n directive: WrTilt,\n inputs: ['maxTilt', 'perspective', 'scale', 'glare'],\n },\n ],\n host: { class: 'wr-tilt-card' },\n})\nexport class WrTiltCard {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { ComponentPortal } from '@angular/cdk/portal';
2
2
  import * as i0 from '@angular/core';
3
3
  import { input, output, signal, computed, inject, ElementRef, ViewEncapsulation, Component, DestroyRef, InjectionToken, Service, makeEnvironmentProviders } from '@angular/core';
4
4
  import { WR_OVERLAY } from 'ngwr/overlay';
5
+ import { useI18nText } from 'ngwr/i18n';
5
6
 
6
7
  /**
7
8
  * @license
@@ -31,6 +32,10 @@ class WrToastItem {
31
32
  /** Auto-dismiss duration in ms — used to scale the progress bar. `0` hides it. */
32
33
  duration = input(0, /* @ts-ignore */
33
34
  ...(ngDevMode ? [{ debugName: "duration" }] : /* istanbul ignore next */ []));
35
+ /**
36
+ * Already resolved by the host — strings, not the config's nullable shape.
37
+ * The item renders them and never reaches for the catalog itself.
38
+ */
34
39
  labels = input.required(/* @ts-ignore */
35
40
  ...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
36
41
  dismissed = output();
@@ -155,6 +160,28 @@ class WrToastHost {
155
160
  /** Layout mode. @default 'stack' (Sonner-style; hover to fan out) */
156
161
  mode = input('stack', /* @ts-ignore */
157
162
  ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
163
+ /**
164
+ * Every string this host and its items render, resolved through the catalog.
165
+ *
166
+ * The config value WINS when the consumer sets one, and its default is now
167
+ * `null` — until v11 those defaults were English literals, so the four
168
+ * `toast.*` keys in the shipped catalogs were dead and a Russian app got an
169
+ * English close button. `region` had no key at all: the live region's name
170
+ * was the literal `'Notifications'` in a host binding.
171
+ */
172
+ regionLabel = useI18nText(signal(null), 'toast.region', 'Notifications');
173
+ closeLabel = useI18nText(computed(() => this.config().labels.close), 'toast.close', 'Close');
174
+ copyLabel = useI18nText(computed(() => this.config().labels.copy), 'toast.copy', 'Copy');
175
+ copiedLabel = useI18nText(computed(() => this.config().labels.copied), 'toast.copied', 'Copied');
176
+ closeAllLabel = useI18nText(computed(() => this.config().labels.closeAll), 'toast.closeAll', 'Close all');
177
+ /** What `wr-toast-item` receives — resolved, so the item stays presentational. */
178
+ labels = computed(() => ({
179
+ close: this.closeLabel(),
180
+ copy: this.copyLabel(),
181
+ copied: this.copiedLabel(),
182
+ closeAll: this.closeAllLabel(),
183
+ }), /* @ts-ignore */
184
+ ...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
158
185
  /** @internal — hovering or focusing the stack toggles this in stack mode. */
159
186
  expanded = signal(false, /* @ts-ignore */
160
187
  ...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
@@ -257,19 +284,19 @@ class WrToastHost {
257
284
  return t.showCopy ?? this.config().showCopy;
258
285
  }
259
286
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrToastHost, deps: [], target: i0.ɵɵFactoryTarget.Component });
260
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrToastHost, isStandalone: true, selector: "wr-toast-host", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed", pauseRequested: "pauseRequested", resumeRequested: "resumeRequested", dismissAllRequested: "dismissAllRequested" }, host: { attributes: { "role": "region", "aria-label": "Notifications" }, listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "focusin": "onFocusIn()", "focusout": "onFocusOut()" }, properties: { "class": "classes()" } }, ngImport: i0, template: "@if (closeAllVisible()) {\n <button type=\"button\" class=\"wr-toast-host__close-all\" (click)=\"dismissAllRequested.emit()\">\n {{ config().labels.closeAll }} ({{ totalCount() }})\n </button>\n}\n\n@for (toast of toasts(); track toast.id) {\n <wr-toast\n [style.--wr-toast-stack-index]=\"stackIndex($index)\"\n [type]=\"toast.type ?? 'info'\"\n [title]=\"toast.title ?? null\"\n [message]=\"toast.message\"\n [dismissible]=\"toast.dismissible ?? true\"\n [showProgress]=\"showProgressFor(toast)\"\n [showCopy]=\"showCopyFor(toast)\"\n [duration]=\"toast.resolvedDuration\"\n [labels]=\"config().labels\"\n (dismissed)=\"dismissed.emit(toast.id)\"\n (pauseRequested)=\"pauseRequested.emit(toast.id)\"\n (resumeRequested)=\"resumeRequested.emit(toast.id)\"\n />\n}\n", dependencies: [{ kind: "component", type: WrToastItem, selector: "wr-toast", inputs: ["type", "title", "message", "dismissible", "showProgress", "showCopy", "duration", "labels"], outputs: ["dismissed", "pauseRequested", "resumeRequested"] }], encapsulation: i0.ViewEncapsulation.None });
287
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrToastHost, isStandalone: true, selector: "wr-toast-host", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed", pauseRequested: "pauseRequested", resumeRequested: "resumeRequested", dismissAllRequested: "dismissAllRequested" }, host: { attributes: { "role": "region" }, listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "focusin": "onFocusIn()", "focusout": "onFocusOut()" }, properties: { "class": "classes()", "attr.aria-label": "regionLabel()" } }, ngImport: i0, template: "@if (closeAllVisible()) {\n <button type=\"button\" class=\"wr-toast-host__close-all\" (click)=\"dismissAllRequested.emit()\">\n {{ closeAllLabel() }} ({{ totalCount() }})\n </button>\n}\n\n@for (toast of toasts(); track toast.id) {\n <wr-toast\n [style.--wr-toast-stack-index]=\"stackIndex($index)\"\n [type]=\"toast.type ?? 'info'\"\n [title]=\"toast.title ?? null\"\n [message]=\"toast.message\"\n [dismissible]=\"toast.dismissible ?? true\"\n [showProgress]=\"showProgressFor(toast)\"\n [showCopy]=\"showCopyFor(toast)\"\n [duration]=\"toast.resolvedDuration\"\n [labels]=\"labels()\"\n (dismissed)=\"dismissed.emit(toast.id)\"\n (pauseRequested)=\"pauseRequested.emit(toast.id)\"\n (resumeRequested)=\"resumeRequested.emit(toast.id)\"\n />\n}\n", dependencies: [{ kind: "component", type: WrToastItem, selector: "wr-toast", inputs: ["type", "title", "message", "dismissible", "showProgress", "showCopy", "duration", "labels"], outputs: ["dismissed", "pauseRequested", "resumeRequested"] }], encapsulation: i0.ViewEncapsulation.None });
261
288
  }
262
289
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrToastHost, decorators: [{
263
290
  type: Component,
264
291
  args: [{ selector: 'wr-toast-host', encapsulation: ViewEncapsulation.None, host: {
265
292
  '[class]': 'classes()',
266
293
  role: 'region',
267
- 'aria-label': 'Notifications',
294
+ '[attr.aria-label]': 'regionLabel()',
268
295
  '(mouseenter)': 'onMouseEnter()',
269
296
  '(mouseleave)': 'onMouseLeave()',
270
297
  '(focusin)': 'onFocusIn()',
271
298
  '(focusout)': 'onFocusOut()',
272
- }, imports: [WrToastItem], template: "@if (closeAllVisible()) {\n <button type=\"button\" class=\"wr-toast-host__close-all\" (click)=\"dismissAllRequested.emit()\">\n {{ config().labels.closeAll }} ({{ totalCount() }})\n </button>\n}\n\n@for (toast of toasts(); track toast.id) {\n <wr-toast\n [style.--wr-toast-stack-index]=\"stackIndex($index)\"\n [type]=\"toast.type ?? 'info'\"\n [title]=\"toast.title ?? null\"\n [message]=\"toast.message\"\n [dismissible]=\"toast.dismissible ?? true\"\n [showProgress]=\"showProgressFor(toast)\"\n [showCopy]=\"showCopyFor(toast)\"\n [duration]=\"toast.resolvedDuration\"\n [labels]=\"config().labels\"\n (dismissed)=\"dismissed.emit(toast.id)\"\n (pauseRequested)=\"pauseRequested.emit(toast.id)\"\n (resumeRequested)=\"resumeRequested.emit(toast.id)\"\n />\n}\n" }]
299
+ }, imports: [WrToastItem], template: "@if (closeAllVisible()) {\n <button type=\"button\" class=\"wr-toast-host__close-all\" (click)=\"dismissAllRequested.emit()\">\n {{ closeAllLabel() }} ({{ totalCount() }})\n </button>\n}\n\n@for (toast of toasts(); track toast.id) {\n <wr-toast\n [style.--wr-toast-stack-index]=\"stackIndex($index)\"\n [type]=\"toast.type ?? 'info'\"\n [title]=\"toast.title ?? null\"\n [message]=\"toast.message\"\n [dismissible]=\"toast.dismissible ?? true\"\n [showProgress]=\"showProgressFor(toast)\"\n [showCopy]=\"showCopyFor(toast)\"\n [duration]=\"toast.resolvedDuration\"\n [labels]=\"labels()\"\n (dismissed)=\"dismissed.emit(toast.id)\"\n (pauseRequested)=\"pauseRequested.emit(toast.id)\"\n (resumeRequested)=\"resumeRequested.emit(toast.id)\"\n />\n}\n" }]
273
300
  }], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }], pauseRequested: [{ type: i0.Output, args: ["pauseRequested"] }], resumeRequested: [{ type: i0.Output, args: ["resumeRequested"] }], dismissAllRequested: [{ type: i0.Output, args: ["dismissAllRequested"] }] } });
274
301
 
275
302
  /**
@@ -318,11 +345,13 @@ const DEFAULT_TOAST_CONFIG = {
318
345
  showCloseAll: true,
319
346
  closeAllThreshold: 2,
320
347
  maxStack: 5,
348
+ // Null, not English: the host resolves each one through the i18n catalog and
349
+ // falls back to English only if nothing is registered. See `WrToastConfig`.
321
350
  labels: {
322
- close: 'Close',
323
- copy: 'Copy',
324
- copied: 'Copied',
325
- closeAll: 'Close all',
351
+ close: null,
352
+ copy: null,
353
+ copied: null,
354
+ closeAll: null,
326
355
  },
327
356
  };
328
357
 
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-toast.mjs","sources":["../../../projects/lib/toast/toast-item.ts","../../../projects/lib/toast/toast-item.html","../../../projects/lib/toast/toast-host.ts","../../../projects/lib/toast/toast-host.html","../../../projects/lib/toast/toast-ref.ts","../../../projects/lib/toast/default-toast-config.ts","../../../projects/lib/toast/tokens/toast-config.token.ts","../../../projects/lib/toast/services/toast.ts","../../../projects/lib/toast/provide-wr-toast-config.ts","../../../projects/lib/toast/ngwr-toast.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ElementRef, ViewEncapsulation, computed, inject, input, output, signal } from '@angular/core';\n\nimport type { WrToastConfig, WrToastType } from './interfaces';\n\n/**\n * One toast row inside the toast host. Not used directly — see\n * `WrToast.show()`.\n *\n * @internal\n */\n@Component({\n selector: 'wr-toast',\n templateUrl: './toast-item.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n '[style.--wr-toast-duration]': 'durationMs()',\n '[style.transform]': 'swipeTransform()',\n '[style.opacity]': 'swipeOpacity()',\n '[style.transition]': 'swiping() ? \"none\" : null',\n '[attr.role]': 'liveRole()',\n '[attr.aria-live]': 'liveLevel()',\n '(mouseenter)': 'pauseRequested.emit()',\n '(mouseleave)': 'resumeRequested.emit()',\n '(touchstart)': 'onSwipeStart($event)',\n '(touchmove)': 'onSwipeMove($event)',\n '(touchend)': 'onSwipeEnd()',\n '(touchcancel)': 'onSwipeEnd()',\n },\n})\nexport class WrToastItem {\n readonly type = input<WrToastType>('info');\n readonly title = input<string | null>(null);\n readonly message = input.required<string>();\n readonly dismissible = input<boolean>(true);\n readonly showProgress = input<boolean>(false);\n readonly showCopy = input<boolean>(false);\n /** Auto-dismiss duration in ms — used to scale the progress bar. `0` hides it. */\n readonly duration = input<number>(0);\n readonly labels = input.required<WrToastConfig['labels']>();\n\n readonly dismissed = output<void>();\n readonly pauseRequested = output<void>();\n readonly resumeRequested = output<void>();\n\n /** True for ~1.5s after a successful copy; flips the icon to a check. */\n protected readonly justCopied = signal(false);\n private copyResetTimer: ReturnType<typeof setTimeout> | null = null;\n\n protected readonly classes = computed(() => `wr-toast wr-toast--${this.type()}`);\n\n /** Escalate to `alert`/`assertive` for danger/warning toasts. */\n protected readonly liveRole = computed(() => (this.type() === 'danger' ? 'alert' : 'status'));\n protected readonly liveLevel = computed(() =>\n this.type() === 'danger' || this.type() === 'warning' ? 'assertive' : 'polite'\n );\n\n /** Inline CSS value for `--wr-toast-duration`. */\n protected readonly durationMs = computed(() => `${this.duration()}ms`);\n\n protected readonly progressVisible = computed(() => this.showProgress() && this.duration() > 0);\n\n protected async onCopy(): Promise<void> {\n try {\n await navigator.clipboard.writeText(this.message());\n this.justCopied.set(true);\n if (this.copyResetTimer) clearTimeout(this.copyResetTimer);\n this.copyResetTimer = setTimeout(() => this.justCopied.set(false), 1500);\n } catch {\n // Clipboard unavailable (insecure context / permission denied) — silent.\n }\n }\n\n // Swipe-sideways-to-dismiss. The toast follows the finger and fades; releasing\n // past 40% of its width emits `dismissed`, otherwise it snaps back.\n private readonly elRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private swipeStartX = 0;\n private swipeWidth = 0;\n protected readonly swipeX = signal(0);\n protected readonly swiping = signal(false);\n\n protected readonly swipeTransform = computed(() => (this.swipeX() === 0 ? null : `translateX(${this.swipeX()}px)`));\n protected readonly swipeOpacity = computed(() => {\n const dist = Math.abs(this.swipeX());\n return dist === 0 ? null : Math.max(0, 1 - dist / (this.swipeWidth || 1));\n });\n\n protected onSwipeStart(event: TouchEvent): void {\n if (!this.dismissible()) return;\n const touch = event.touches[0];\n if (!touch) return;\n this.swipeStartX = touch.clientX;\n this.swipeWidth = this.elRef.nativeElement.offsetWidth;\n this.swiping.set(true);\n }\n\n protected onSwipeMove(event: TouchEvent): void {\n if (!this.swiping()) return;\n const touch = event.touches[0];\n if (!touch) return;\n this.swipeX.set(touch.clientX - this.swipeStartX);\n }\n\n protected onSwipeEnd(): void {\n if (!this.swiping()) return;\n this.swiping.set(false);\n if (Math.abs(this.swipeX()) > (this.swipeWidth || 0) * 0.4) {\n this.dismissed.emit();\n } else {\n this.swipeX.set(0);\n }\n }\n}\n","<div class=\"wr-toast__body\">\n @if (title(); as text) {\n <p class=\"wr-toast__title\">{{ text }}</p>\n }\n <p class=\"wr-toast__message\">{{ message() }}</p>\n</div>\n\n<div class=\"wr-toast__actions\">\n @if (showCopy()) {\n <button\n type=\"button\"\n class=\"wr-toast__action wr-toast__action--copy\"\n [attr.aria-label]=\"justCopied() ? labels().copied : labels().copy\"\n [title]=\"justCopied() ? labels().copied : labels().copy\"\n (click)=\"onCopy()\"\n >\n @if (justCopied()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n }\n </button>\n }\n\n @if (dismissible()) {\n <button\n type=\"button\"\n class=\"wr-toast__action wr-toast__action--close\"\n [attr.aria-label]=\"labels().close\"\n [title]=\"labels().close\"\n (click)=\"dismissed.emit()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n</div>\n\n@if (progressVisible()) {\n <span class=\"wr-toast__progress\" aria-hidden=\"true\"></span>\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, DestroyRef, ViewEncapsulation, computed, inject, input, output, signal } from '@angular/core';\n\nimport type { WrToastConfig, WrToastMode, WrToastOptions, WrToastPosition } from './interfaces';\nimport { WrToastItem } from './toast-item';\n\n/** ms before the pointer or focus leaving actually collapses the stack. Buffers\n * the cursor briefly leaving the host as toasts reflow underneath it, and focus\n * hopping between two buttons inside the host. */\nconst COLLAPSE_DELAY_MS = 120;\n\n/** Active entry pushed by the service — adds the bookkeeping fields the host renders. */\ntype ActiveToast = WrToastOptions & {\n readonly id: number;\n readonly resolvedDuration: number;\n};\n\n/**\n * Internal host that lives inside the toast overlay and renders the\n * active stack. Owned by `WrToast`.\n *\n * @internal\n */\n@Component({\n selector: 'wr-toast-host',\n templateUrl: './toast-host.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n role: 'region',\n 'aria-label': 'Notifications',\n '(mouseenter)': 'onMouseEnter()',\n '(mouseleave)': 'onMouseLeave()',\n '(focusin)': 'onFocusIn()',\n '(focusout)': 'onFocusOut()',\n },\n imports: [WrToastItem],\n})\nexport class WrToastHost {\n readonly position = input<WrToastPosition>('top-end');\n readonly config = input.required<WrToastConfig>();\n /** Layout mode. @default 'stack' (Sonner-style; hover to fan out) */\n readonly mode = input<WrToastMode>('stack');\n\n /** @internal — hovering or focusing the stack toggles this in stack mode. */\n protected readonly expanded = signal(false);\n\n /** Pointer is over the host. */\n private readonly hovered = signal(false);\n /** Focus is somewhere inside the host — keyboard equivalent of hovering, and\n * the only way a keyboard user can reach the \"Close all\" button. */\n private readonly focusWithin = signal(false);\n\n private readonly destroyRef = inject(DestroyRef);\n private collapseTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n this.destroyRef.onDestroy(() => this.clearCollapseTimer());\n }\n\n /** @internal */\n protected onMouseEnter(): void {\n this.hovered.set(true);\n this.syncExpanded();\n }\n\n /** @internal */\n protected onMouseLeave(): void {\n this.hovered.set(false);\n this.syncExpanded();\n }\n\n /** @internal */\n protected onFocusIn(): void {\n this.focusWithin.set(true);\n this.syncExpanded();\n }\n\n /** @internal */\n protected onFocusOut(): void {\n this.focusWithin.set(false);\n this.syncExpanded();\n }\n\n /** Expand immediately while the pointer or focus is inside, and delay the\n * collapse so a cursor briefly slipping off the host during a layout reflow\n * — or focus moving between two buttons inside it — doesn't cause a flicker. */\n private syncExpanded(): void {\n if (this.hovered() || this.focusWithin()) {\n this.clearCollapseTimer();\n this.expanded.set(true);\n return;\n }\n if (this.collapseTimer !== null) return;\n this.collapseTimer = setTimeout(() => {\n this.collapseTimer = null;\n if (!this.hovered() && !this.focusWithin()) this.expanded.set(false);\n }, COLLAPSE_DELAY_MS);\n }\n\n private clearCollapseTimer(): void {\n if (this.collapseTimer !== null) {\n clearTimeout(this.collapseTimer);\n this.collapseTimer = null;\n }\n }\n\n /** @internal — pushed by the service: the rendered (capped) stack. */\n readonly toasts = signal<readonly ActiveToast[]>([]);\n\n /** @internal — pushed by the service: count still queued behind the cap. */\n readonly queued = signal(0);\n\n /** Total outstanding toasts (visible + queued) — what \"Close all\" clears. */\n protected readonly totalCount = computed(() => this.toasts().length + this.queued());\n\n /** @internal — service listens to update its internal state. */\n readonly dismissed = output<number>();\n readonly pauseRequested = output<number>();\n readonly resumeRequested = output<number>();\n readonly dismissAllRequested = output<void>();\n\n protected readonly classes = computed(() => {\n const parts = ['wr-toast-host', `wr-toast-host--${this.position()}`, `wr-toast-host--${this.mode()}`];\n if (this.mode() === 'stack' && this.expanded()) parts.push('wr-toast-host--expanded');\n return parts.join(' ');\n });\n\n /** Distance from the front of the stack (0 = newest / fully visible). */\n protected stackIndex(i: number): number {\n return this.toasts().length - 1 - i;\n }\n\n protected readonly closeAllVisible = computed(() => {\n const cfg = this.config();\n // In stack mode the toasts cascade absolutely while collapsed, which\n // makes the close-all button jump between layout positions on hover\n // (button moves → cursor leaves → host collapses → cycle = blink).\n // Only show it once the stack is expanded — by hover OR by focus entering\n // it, so it stays reachable from the keyboard — or always in list mode.\n if (this.mode() === 'stack' && !this.expanded()) return false;\n return cfg.showCloseAll && this.toasts().length >= cfg.closeAllThreshold;\n });\n\n protected showProgressFor(t: WrToastOptions): boolean {\n return t.showProgress ?? this.config().showProgress;\n }\n\n protected showCopyFor(t: WrToastOptions): boolean {\n return t.showCopy ?? this.config().showCopy;\n }\n}\n","@if (closeAllVisible()) {\n <button type=\"button\" class=\"wr-toast-host__close-all\" (click)=\"dismissAllRequested.emit()\">\n {{ config().labels.closeAll }} ({{ totalCount() }})\n </button>\n}\n\n@for (toast of toasts(); track toast.id) {\n <wr-toast\n [style.--wr-toast-stack-index]=\"stackIndex($index)\"\n [type]=\"toast.type ?? 'info'\"\n [title]=\"toast.title ?? null\"\n [message]=\"toast.message\"\n [dismissible]=\"toast.dismissible ?? true\"\n [showProgress]=\"showProgressFor(toast)\"\n [showCopy]=\"showCopyFor(toast)\"\n [duration]=\"toast.resolvedDuration\"\n [labels]=\"config().labels\"\n (dismissed)=\"dismissed.emit(toast.id)\"\n (pauseRequested)=\"pauseRequested.emit(toast.id)\"\n (resumeRequested)=\"resumeRequested.emit(toast.id)\"\n />\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrToastOptions } from './interfaces';\n\n/**\n * Handle returned by `WrToast.show()`. Call `dismiss()` to remove\n * the toast early. Inspect `options` to see what the caller requested.\n */\nexport class WrToastRef {\n constructor(\n public readonly id: number,\n public readonly options: WrToastOptions,\n private readonly onDismiss: (id: number) => void\n ) {}\n\n /** Remove this toast from the stack. */\n dismiss(): void {\n this.onDismiss(this.id);\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrToastConfig } from './interfaces';\n\n/**\n * Library defaults applied when no {@link provideWrToastConfig} call is\n * registered. Merged shallowly with the consumer's overrides (the `labels`\n * sub-object is merged separately so callers can override one string at a\n * time).\n */\nexport const DEFAULT_TOAST_CONFIG: WrToastConfig = {\n position: 'top-end',\n mode: 'stack',\n duration: 4000,\n showProgress: true,\n showCopy: false,\n showCloseAll: true,\n closeAllThreshold: 2,\n maxStack: 5,\n labels: {\n close: 'Close',\n copy: 'Copy',\n copied: 'Copied',\n closeAll: 'Close all',\n },\n};\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { DEFAULT_TOAST_CONFIG } from '../default-toast-config';\nimport type { WrToastConfig } from '../interfaces';\n\n/**\n * Holds the global {@link WrToastConfig} used by {@link WrToast}.\n * The default factory returns {@link DEFAULT_TOAST_CONFIG} so the service\n * works out of the box; override via {@link provideWrToastConfig}.\n */\nexport const WR_TOAST_CONFIG = new InjectionToken<WrToastConfig>('WR_TOAST_CONFIG', {\n providedIn: 'root',\n factory: () => DEFAULT_TOAST_CONFIG,\n});\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { type ComponentRef, Service, inject } from '@angular/core';\n\nimport { WR_OVERLAY } from 'ngwr/overlay';\n\nimport type { WrToastOptions, WrToastPosition } from '../interfaces';\nimport { WrToastHost } from '../toast-host';\nimport { WrToastRef } from '../toast-ref';\nimport { WR_TOAST_CONFIG } from '../tokens';\n\ntype ActiveEntry = WrToastOptions & {\n readonly id: number;\n /** Resolved auto-dismiss duration in ms after merging with global config. */\n readonly resolvedDuration: number;\n /** Resolved corner for this stack. */\n readonly resolvedPosition: WrToastPosition;\n /** Pending timeout handle. */\n timer?: ReturnType<typeof setTimeout>;\n /** Timestamp of the last timer (re)start, used to compute remaining on pause. */\n startedAt?: number;\n /** Milliseconds left when paused. */\n remaining: number;\n};\n\n/**\n * Opens toast notifications in a single shared overlay.\n *\n * Global defaults come from {@link WR_TOAST_CONFIG}; register\n * {@link provideWrToastConfig} once at bootstrap to customise. Each\n * `show()` call accepts per-toast overrides via {@link WrToastOptions}.\n *\n * @example\n * ```ts\n * const toast = inject(WrToast);\n *\n * toast.show({ type: 'success', title: 'Saved', message: 'Profile updated.' });\n * toast.show({ type: 'danger', message: 'Network error', duration: 0 });\n * toast.show({ message: 'Permalink copied', position: 'bottom', showCopy: true });\n * ```\n *\n * @see https://ngwr.dev/reference/components/toast\n */\n@Service()\nexport class WrToast {\n private readonly overlay = inject(WR_OVERLAY);\n private readonly config = inject(WR_TOAST_CONFIG);\n\n private overlayRef: OverlayRef | null = null;\n private hostRef: ComponentRef<WrToastHost> | null = null;\n private currentPosition: WrToastPosition = this.config.position;\n private currentMode: 'stack' | 'list' = this.config.mode;\n private nextId = 1;\n /** Currently rendered toasts (capped at `config.maxStack`). */\n private active: ActiveEntry[] = [];\n /** Overflow waiting for a free slot — promoted FIFO as actives dismiss, so\n * nothing is ever silently dropped. */\n private queue: ActiveEntry[] = [];\n\n /** Open a toast. Returns a handle you can `dismiss()` early. */\n show(options: WrToastOptions): WrToastRef {\n const resolvedPosition = options.position ?? this.config.position;\n const resolvedDuration = options.duration ?? this.config.duration;\n\n this.ensureHost(resolvedPosition);\n\n const entry: ActiveEntry = {\n ...options,\n id: this.nextId++,\n resolvedDuration,\n resolvedPosition,\n remaining: resolvedDuration,\n };\n\n const max = this.config.maxStack;\n if (max > 0 && this.active.length >= max) {\n // Stack is full — hold this one in the queue (no timer until it's shown).\n this.queue = [...this.queue, entry];\n this.pushToHost();\n } else {\n this.active = [...this.active, entry];\n this.pushToHost();\n this.startTimer(entry);\n }\n\n return new WrToastRef(entry.id, options, id => this.dismiss(id));\n }\n\n /** Dismiss a single toast by id. */\n dismiss(id: number): void {\n const entry = this.active.find(t => t.id === id);\n if (entry?.timer) clearTimeout(entry.timer);\n this.active = this.active.filter(t => t.id !== id);\n // A dismiss can also target a still-queued toast.\n this.queue = this.queue.filter(t => t.id !== id);\n this.promoteFromQueue();\n this.pushToHost();\n if (this.active.length === 0 && this.queue.length === 0) this.disposeHost();\n }\n\n /** Dismiss every visible toast. Wired to the host's \"Close all\" button. */\n dismissAll(): void {\n for (const entry of this.active) {\n if (entry.timer) clearTimeout(entry.timer);\n }\n this.active = [];\n this.queue = [];\n this.disposeHost();\n }\n\n /** Change the corner the stack opens in. Affects future toasts. */\n setPosition(position: WrToastPosition): void {\n this.currentPosition = position;\n if (this.hostRef) this.hostRef.setInput('position', position);\n }\n\n /** Switch the layout mode at runtime. Persists across host re-creation. */\n setMode(mode: 'stack' | 'list'): void {\n this.currentMode = mode;\n if (this.hostRef) this.hostRef.setInput('mode', mode);\n }\n\n // Timer\n\n private startTimer(entry: ActiveEntry): void {\n if (entry.remaining <= 0) return;\n entry.startedAt = Date.now();\n entry.timer = setTimeout(() => this.dismiss(entry.id), entry.remaining);\n }\n\n private pauseTimer(entry: ActiveEntry): void {\n if (!entry.timer) return;\n clearTimeout(entry.timer);\n entry.timer = undefined;\n if (entry.startedAt) {\n entry.remaining = Math.max(0, entry.remaining - (Date.now() - entry.startedAt));\n }\n }\n\n // Host plumbing\n\n private ensureHost(position: WrToastPosition): void {\n if (this.overlayRef) {\n if (position !== this.currentPosition) this.setPosition(position);\n return;\n }\n\n this.currentPosition = position;\n\n this.overlayRef = this.overlay.create({\n positionStrategy: this.overlay.position().global(),\n scrollStrategy: this.overlay.scrollStrategies.noop(),\n hasBackdrop: false,\n panelClass: ['wr-toast-overlay'],\n });\n\n const portal = new ComponentPortal(WrToastHost);\n this.hostRef = this.overlayRef.attach(portal);\n this.hostRef.setInput('position', position);\n this.hostRef.setInput('mode', this.currentMode);\n this.hostRef.setInput('config', this.config);\n\n const inst = this.hostRef.instance;\n inst.dismissed.subscribe(id => this.dismiss(id));\n inst.dismissAllRequested.subscribe(() => this.dismissAll());\n inst.pauseRequested.subscribe(id => {\n const entry = this.active.find(t => t.id === id);\n if (entry) this.pauseTimer(entry);\n });\n inst.resumeRequested.subscribe(id => {\n const entry = this.active.find(t => t.id === id);\n if (entry) this.startTimer(entry);\n });\n }\n\n /** Fill any free stack slots from the queue (FIFO), starting each promoted\n * toast's auto-dismiss timer only as it becomes visible. */\n private promoteFromQueue(): void {\n const max = this.config.maxStack;\n while ((max <= 0 || this.active.length < max) && this.queue.length > 0) {\n const [next, ...rest] = this.queue;\n this.queue = rest;\n this.active = [...this.active, next];\n this.startTimer(next);\n }\n }\n\n private pushToHost(): void {\n this.hostRef?.instance.toasts.set([...this.active]);\n this.hostRef?.instance.queued.set(this.queue.length);\n }\n\n private disposeHost(): void {\n if (this.overlayRef) {\n this.overlayRef.dispose();\n this.overlayRef = null;\n this.hostRef = null;\n }\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\n\nimport { DEFAULT_TOAST_CONFIG } from './default-toast-config';\nimport type { WrToastConfig } from './interfaces';\nimport { WR_TOAST_CONFIG } from './tokens';\n\n/**\n * Registers a global {@link WrToastConfig} for {@link WrToast}. Any\n * field you omit falls back to {@link DEFAULT_TOAST_CONFIG}; the `labels`\n * sub-object is merged separately so you can override a single string at a\n * time (useful for i18n).\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrToastConfig({\n * position: 'bottom-end',\n * showCopy: true,\n * maxStack: 3,\n * labels: { close: 'Закрыть' },\n * }),\n * ],\n * });\n * ```\n */\nexport function provideWrToastConfig(\n config: Partial<Omit<WrToastConfig, 'labels'>> & { readonly labels?: Partial<WrToastConfig['labels']> }\n): EnvironmentProviders {\n const merged: WrToastConfig = {\n ...DEFAULT_TOAST_CONFIG,\n ...config,\n labels: { ...DEFAULT_TOAST_CONFIG.labels, ...config.labels },\n };\n return makeEnvironmentProviders([{ provide: WR_TOAST_CONFIG, useValue: merged }]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-toast.mjs","sources":["../../../projects/lib/toast/toast-item.ts","../../../projects/lib/toast/toast-item.html","../../../projects/lib/toast/toast-host.ts","../../../projects/lib/toast/toast-host.html","../../../projects/lib/toast/toast-ref.ts","../../../projects/lib/toast/default-toast-config.ts","../../../projects/lib/toast/tokens/toast-config.token.ts","../../../projects/lib/toast/services/toast.ts","../../../projects/lib/toast/provide-wr-toast-config.ts","../../../projects/lib/toast/ngwr-toast.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ElementRef, ViewEncapsulation, computed, inject, input, output, signal } from '@angular/core';\n\nimport type { WrToastConfig, WrToastType } from './interfaces';\n\n/**\n * One toast row inside the toast host. Not used directly — see\n * `WrToast.show()`.\n *\n * @internal\n */\n@Component({\n selector: 'wr-toast',\n templateUrl: './toast-item.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n '[style.--wr-toast-duration]': 'durationMs()',\n '[style.transform]': 'swipeTransform()',\n '[style.opacity]': 'swipeOpacity()',\n '[style.transition]': 'swiping() ? \"none\" : null',\n '[attr.role]': 'liveRole()',\n '[attr.aria-live]': 'liveLevel()',\n '(mouseenter)': 'pauseRequested.emit()',\n '(mouseleave)': 'resumeRequested.emit()',\n '(touchstart)': 'onSwipeStart($event)',\n '(touchmove)': 'onSwipeMove($event)',\n '(touchend)': 'onSwipeEnd()',\n '(touchcancel)': 'onSwipeEnd()',\n },\n})\nexport class WrToastItem {\n readonly type = input<WrToastType>('info');\n readonly title = input<string | null>(null);\n readonly message = input.required<string>();\n readonly dismissible = input<boolean>(true);\n readonly showProgress = input<boolean>(false);\n readonly showCopy = input<boolean>(false);\n /** Auto-dismiss duration in ms — used to scale the progress bar. `0` hides it. */\n readonly duration = input<number>(0);\n /**\n * Already resolved by the host — strings, not the config's nullable shape.\n * The item renders them and never reaches for the catalog itself.\n */\n readonly labels = input.required<{ [K in keyof WrToastConfig['labels']]: string }>();\n\n readonly dismissed = output<void>();\n readonly pauseRequested = output<void>();\n readonly resumeRequested = output<void>();\n\n /** True for ~1.5s after a successful copy; flips the icon to a check. */\n protected readonly justCopied = signal(false);\n private copyResetTimer: ReturnType<typeof setTimeout> | null = null;\n\n protected readonly classes = computed(() => `wr-toast wr-toast--${this.type()}`);\n\n /** Escalate to `alert`/`assertive` for danger/warning toasts. */\n protected readonly liveRole = computed(() => (this.type() === 'danger' ? 'alert' : 'status'));\n protected readonly liveLevel = computed(() =>\n this.type() === 'danger' || this.type() === 'warning' ? 'assertive' : 'polite'\n );\n\n /** Inline CSS value for `--wr-toast-duration`. */\n protected readonly durationMs = computed(() => `${this.duration()}ms`);\n\n protected readonly progressVisible = computed(() => this.showProgress() && this.duration() > 0);\n\n protected async onCopy(): Promise<void> {\n try {\n await navigator.clipboard.writeText(this.message());\n this.justCopied.set(true);\n if (this.copyResetTimer) clearTimeout(this.copyResetTimer);\n this.copyResetTimer = setTimeout(() => this.justCopied.set(false), 1500);\n } catch {\n // Clipboard unavailable (insecure context / permission denied) — silent.\n }\n }\n\n // Swipe-sideways-to-dismiss. The toast follows the finger and fades; releasing\n // past 40% of its width emits `dismissed`, otherwise it snaps back.\n private readonly elRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private swipeStartX = 0;\n private swipeWidth = 0;\n protected readonly swipeX = signal(0);\n protected readonly swiping = signal(false);\n\n protected readonly swipeTransform = computed(() => (this.swipeX() === 0 ? null : `translateX(${this.swipeX()}px)`));\n protected readonly swipeOpacity = computed(() => {\n const dist = Math.abs(this.swipeX());\n return dist === 0 ? null : Math.max(0, 1 - dist / (this.swipeWidth || 1));\n });\n\n protected onSwipeStart(event: TouchEvent): void {\n if (!this.dismissible()) return;\n const touch = event.touches[0];\n if (!touch) return;\n this.swipeStartX = touch.clientX;\n this.swipeWidth = this.elRef.nativeElement.offsetWidth;\n this.swiping.set(true);\n }\n\n protected onSwipeMove(event: TouchEvent): void {\n if (!this.swiping()) return;\n const touch = event.touches[0];\n if (!touch) return;\n this.swipeX.set(touch.clientX - this.swipeStartX);\n }\n\n protected onSwipeEnd(): void {\n if (!this.swiping()) return;\n this.swiping.set(false);\n if (Math.abs(this.swipeX()) > (this.swipeWidth || 0) * 0.4) {\n this.dismissed.emit();\n } else {\n this.swipeX.set(0);\n }\n }\n}\n","<div class=\"wr-toast__body\">\n @if (title(); as text) {\n <p class=\"wr-toast__title\">{{ text }}</p>\n }\n <p class=\"wr-toast__message\">{{ message() }}</p>\n</div>\n\n<div class=\"wr-toast__actions\">\n @if (showCopy()) {\n <button\n type=\"button\"\n class=\"wr-toast__action wr-toast__action--copy\"\n [attr.aria-label]=\"justCopied() ? labels().copied : labels().copy\"\n [title]=\"justCopied() ? labels().copied : labels().copy\"\n (click)=\"onCopy()\"\n >\n @if (justCopied()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n }\n </button>\n }\n\n @if (dismissible()) {\n <button\n type=\"button\"\n class=\"wr-toast__action wr-toast__action--close\"\n [attr.aria-label]=\"labels().close\"\n [title]=\"labels().close\"\n (click)=\"dismissed.emit()\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </button>\n }\n</div>\n\n@if (progressVisible()) {\n <span class=\"wr-toast__progress\" aria-hidden=\"true\"></span>\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, DestroyRef, ViewEncapsulation, computed, inject, input, output, signal } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\nimport type { WrToastConfig, WrToastMode, WrToastOptions, WrToastPosition } from './interfaces';\nimport { WrToastItem } from './toast-item';\n\n/** ms before the pointer or focus leaving actually collapses the stack. Buffers\n * the cursor briefly leaving the host as toasts reflow underneath it, and focus\n * hopping between two buttons inside the host. */\nconst COLLAPSE_DELAY_MS = 120;\n\n/** Active entry pushed by the service — adds the bookkeeping fields the host renders. */\ntype ActiveToast = WrToastOptions & {\n readonly id: number;\n readonly resolvedDuration: number;\n};\n\n/**\n * Internal host that lives inside the toast overlay and renders the\n * active stack. Owned by `WrToast`.\n *\n * @internal\n */\n@Component({\n selector: 'wr-toast-host',\n templateUrl: './toast-host.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n role: 'region',\n '[attr.aria-label]': 'regionLabel()',\n '(mouseenter)': 'onMouseEnter()',\n '(mouseleave)': 'onMouseLeave()',\n '(focusin)': 'onFocusIn()',\n '(focusout)': 'onFocusOut()',\n },\n imports: [WrToastItem],\n})\nexport class WrToastHost {\n readonly position = input<WrToastPosition>('top-end');\n readonly config = input.required<WrToastConfig>();\n /** Layout mode. @default 'stack' (Sonner-style; hover to fan out) */\n readonly mode = input<WrToastMode>('stack');\n\n /**\n * Every string this host and its items render, resolved through the catalog.\n *\n * The config value WINS when the consumer sets one, and its default is now\n * `null` — until v11 those defaults were English literals, so the four\n * `toast.*` keys in the shipped catalogs were dead and a Russian app got an\n * English close button. `region` had no key at all: the live region's name\n * was the literal `'Notifications'` in a host binding.\n */\n protected readonly regionLabel = useI18nText(signal(null), 'toast.region', 'Notifications');\n\n private readonly closeLabel = useI18nText(\n computed(() => this.config().labels.close),\n 'toast.close',\n 'Close'\n );\n private readonly copyLabel = useI18nText(\n computed(() => this.config().labels.copy),\n 'toast.copy',\n 'Copy'\n );\n private readonly copiedLabel = useI18nText(\n computed(() => this.config().labels.copied),\n 'toast.copied',\n 'Copied'\n );\n protected readonly closeAllLabel = useI18nText(\n computed(() => this.config().labels.closeAll),\n 'toast.closeAll',\n 'Close all'\n );\n\n /** What `wr-toast-item` receives — resolved, so the item stays presentational. */\n protected readonly labels = computed(() => ({\n close: this.closeLabel(),\n copy: this.copyLabel(),\n copied: this.copiedLabel(),\n closeAll: this.closeAllLabel(),\n }));\n\n /** @internal — hovering or focusing the stack toggles this in stack mode. */\n protected readonly expanded = signal(false);\n\n /** Pointer is over the host. */\n private readonly hovered = signal(false);\n /** Focus is somewhere inside the host — keyboard equivalent of hovering, and\n * the only way a keyboard user can reach the \"Close all\" button. */\n private readonly focusWithin = signal(false);\n\n private readonly destroyRef = inject(DestroyRef);\n private collapseTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n this.destroyRef.onDestroy(() => this.clearCollapseTimer());\n }\n\n /** @internal */\n protected onMouseEnter(): void {\n this.hovered.set(true);\n this.syncExpanded();\n }\n\n /** @internal */\n protected onMouseLeave(): void {\n this.hovered.set(false);\n this.syncExpanded();\n }\n\n /** @internal */\n protected onFocusIn(): void {\n this.focusWithin.set(true);\n this.syncExpanded();\n }\n\n /** @internal */\n protected onFocusOut(): void {\n this.focusWithin.set(false);\n this.syncExpanded();\n }\n\n /** Expand immediately while the pointer or focus is inside, and delay the\n * collapse so a cursor briefly slipping off the host during a layout reflow\n * — or focus moving between two buttons inside it — doesn't cause a flicker. */\n private syncExpanded(): void {\n if (this.hovered() || this.focusWithin()) {\n this.clearCollapseTimer();\n this.expanded.set(true);\n return;\n }\n if (this.collapseTimer !== null) return;\n this.collapseTimer = setTimeout(() => {\n this.collapseTimer = null;\n if (!this.hovered() && !this.focusWithin()) this.expanded.set(false);\n }, COLLAPSE_DELAY_MS);\n }\n\n private clearCollapseTimer(): void {\n if (this.collapseTimer !== null) {\n clearTimeout(this.collapseTimer);\n this.collapseTimer = null;\n }\n }\n\n /** @internal — pushed by the service: the rendered (capped) stack. */\n readonly toasts = signal<readonly ActiveToast[]>([]);\n\n /** @internal — pushed by the service: count still queued behind the cap. */\n readonly queued = signal(0);\n\n /** Total outstanding toasts (visible + queued) — what \"Close all\" clears. */\n protected readonly totalCount = computed(() => this.toasts().length + this.queued());\n\n /** @internal — service listens to update its internal state. */\n readonly dismissed = output<number>();\n readonly pauseRequested = output<number>();\n readonly resumeRequested = output<number>();\n readonly dismissAllRequested = output<void>();\n\n protected readonly classes = computed(() => {\n const parts = ['wr-toast-host', `wr-toast-host--${this.position()}`, `wr-toast-host--${this.mode()}`];\n if (this.mode() === 'stack' && this.expanded()) parts.push('wr-toast-host--expanded');\n return parts.join(' ');\n });\n\n /** Distance from the front of the stack (0 = newest / fully visible). */\n protected stackIndex(i: number): number {\n return this.toasts().length - 1 - i;\n }\n\n protected readonly closeAllVisible = computed(() => {\n const cfg = this.config();\n // In stack mode the toasts cascade absolutely while collapsed, which\n // makes the close-all button jump between layout positions on hover\n // (button moves → cursor leaves → host collapses → cycle = blink).\n // Only show it once the stack is expanded — by hover OR by focus entering\n // it, so it stays reachable from the keyboard — or always in list mode.\n if (this.mode() === 'stack' && !this.expanded()) return false;\n return cfg.showCloseAll && this.toasts().length >= cfg.closeAllThreshold;\n });\n\n protected showProgressFor(t: WrToastOptions): boolean {\n return t.showProgress ?? this.config().showProgress;\n }\n\n protected showCopyFor(t: WrToastOptions): boolean {\n return t.showCopy ?? this.config().showCopy;\n }\n}\n","@if (closeAllVisible()) {\n <button type=\"button\" class=\"wr-toast-host__close-all\" (click)=\"dismissAllRequested.emit()\">\n {{ closeAllLabel() }} ({{ totalCount() }})\n </button>\n}\n\n@for (toast of toasts(); track toast.id) {\n <wr-toast\n [style.--wr-toast-stack-index]=\"stackIndex($index)\"\n [type]=\"toast.type ?? 'info'\"\n [title]=\"toast.title ?? null\"\n [message]=\"toast.message\"\n [dismissible]=\"toast.dismissible ?? true\"\n [showProgress]=\"showProgressFor(toast)\"\n [showCopy]=\"showCopyFor(toast)\"\n [duration]=\"toast.resolvedDuration\"\n [labels]=\"labels()\"\n (dismissed)=\"dismissed.emit(toast.id)\"\n (pauseRequested)=\"pauseRequested.emit(toast.id)\"\n (resumeRequested)=\"resumeRequested.emit(toast.id)\"\n />\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrToastOptions } from './interfaces';\n\n/**\n * Handle returned by `WrToast.show()`. Call `dismiss()` to remove\n * the toast early. Inspect `options` to see what the caller requested.\n */\nexport class WrToastRef {\n constructor(\n public readonly id: number,\n public readonly options: WrToastOptions,\n private readonly onDismiss: (id: number) => void\n ) {}\n\n /** Remove this toast from the stack. */\n dismiss(): void {\n this.onDismiss(this.id);\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrToastConfig } from './interfaces';\n\n/**\n * Library defaults applied when no {@link provideWrToastConfig} call is\n * registered. Merged shallowly with the consumer's overrides (the `labels`\n * sub-object is merged separately so callers can override one string at a\n * time).\n */\nexport const DEFAULT_TOAST_CONFIG: WrToastConfig = {\n position: 'top-end',\n mode: 'stack',\n duration: 4000,\n showProgress: true,\n showCopy: false,\n showCloseAll: true,\n closeAllThreshold: 2,\n maxStack: 5,\n // Null, not English: the host resolves each one through the i18n catalog and\n // falls back to English only if nothing is registered. See `WrToastConfig`.\n labels: {\n close: null,\n copy: null,\n copied: null,\n closeAll: null,\n },\n};\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport { DEFAULT_TOAST_CONFIG } from '../default-toast-config';\nimport type { WrToastConfig } from '../interfaces';\n\n/**\n * Holds the global {@link WrToastConfig} used by {@link WrToast}.\n * The default factory returns {@link DEFAULT_TOAST_CONFIG} so the service\n * works out of the box; override via {@link provideWrToastConfig}.\n */\nexport const WR_TOAST_CONFIG = new InjectionToken<WrToastConfig>('WR_TOAST_CONFIG', {\n providedIn: 'root',\n factory: () => DEFAULT_TOAST_CONFIG,\n});\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { type ComponentRef, Service, inject } from '@angular/core';\n\nimport { WR_OVERLAY } from 'ngwr/overlay';\n\nimport type { WrToastOptions, WrToastPosition } from '../interfaces';\nimport { WrToastHost } from '../toast-host';\nimport { WrToastRef } from '../toast-ref';\nimport { WR_TOAST_CONFIG } from '../tokens';\n\ntype ActiveEntry = WrToastOptions & {\n readonly id: number;\n /** Resolved auto-dismiss duration in ms after merging with global config. */\n readonly resolvedDuration: number;\n /** Resolved corner for this stack. */\n readonly resolvedPosition: WrToastPosition;\n /** Pending timeout handle. */\n timer?: ReturnType<typeof setTimeout>;\n /** Timestamp of the last timer (re)start, used to compute remaining on pause. */\n startedAt?: number;\n /** Milliseconds left when paused. */\n remaining: number;\n};\n\n/**\n * Opens toast notifications in a single shared overlay.\n *\n * Global defaults come from {@link WR_TOAST_CONFIG}; register\n * {@link provideWrToastConfig} once at bootstrap to customise. Each\n * `show()` call accepts per-toast overrides via {@link WrToastOptions}.\n *\n * @example\n * ```ts\n * const toast = inject(WrToast);\n *\n * toast.show({ type: 'success', title: 'Saved', message: 'Profile updated.' });\n * toast.show({ type: 'danger', message: 'Network error', duration: 0 });\n * toast.show({ message: 'Permalink copied', position: 'bottom', showCopy: true });\n * ```\n *\n * @see https://ngwr.dev/reference/components/toast\n */\n@Service()\nexport class WrToast {\n private readonly overlay = inject(WR_OVERLAY);\n private readonly config = inject(WR_TOAST_CONFIG);\n\n private overlayRef: OverlayRef | null = null;\n private hostRef: ComponentRef<WrToastHost> | null = null;\n private currentPosition: WrToastPosition = this.config.position;\n private currentMode: 'stack' | 'list' = this.config.mode;\n private nextId = 1;\n /** Currently rendered toasts (capped at `config.maxStack`). */\n private active: ActiveEntry[] = [];\n /** Overflow waiting for a free slot — promoted FIFO as actives dismiss, so\n * nothing is ever silently dropped. */\n private queue: ActiveEntry[] = [];\n\n /** Open a toast. Returns a handle you can `dismiss()` early. */\n show(options: WrToastOptions): WrToastRef {\n const resolvedPosition = options.position ?? this.config.position;\n const resolvedDuration = options.duration ?? this.config.duration;\n\n this.ensureHost(resolvedPosition);\n\n const entry: ActiveEntry = {\n ...options,\n id: this.nextId++,\n resolvedDuration,\n resolvedPosition,\n remaining: resolvedDuration,\n };\n\n const max = this.config.maxStack;\n if (max > 0 && this.active.length >= max) {\n // Stack is full — hold this one in the queue (no timer until it's shown).\n this.queue = [...this.queue, entry];\n this.pushToHost();\n } else {\n this.active = [...this.active, entry];\n this.pushToHost();\n this.startTimer(entry);\n }\n\n return new WrToastRef(entry.id, options, id => this.dismiss(id));\n }\n\n /** Dismiss a single toast by id. */\n dismiss(id: number): void {\n const entry = this.active.find(t => t.id === id);\n if (entry?.timer) clearTimeout(entry.timer);\n this.active = this.active.filter(t => t.id !== id);\n // A dismiss can also target a still-queued toast.\n this.queue = this.queue.filter(t => t.id !== id);\n this.promoteFromQueue();\n this.pushToHost();\n if (this.active.length === 0 && this.queue.length === 0) this.disposeHost();\n }\n\n /** Dismiss every visible toast. Wired to the host's \"Close all\" button. */\n dismissAll(): void {\n for (const entry of this.active) {\n if (entry.timer) clearTimeout(entry.timer);\n }\n this.active = [];\n this.queue = [];\n this.disposeHost();\n }\n\n /** Change the corner the stack opens in. Affects future toasts. */\n setPosition(position: WrToastPosition): void {\n this.currentPosition = position;\n if (this.hostRef) this.hostRef.setInput('position', position);\n }\n\n /** Switch the layout mode at runtime. Persists across host re-creation. */\n setMode(mode: 'stack' | 'list'): void {\n this.currentMode = mode;\n if (this.hostRef) this.hostRef.setInput('mode', mode);\n }\n\n // Timer\n\n private startTimer(entry: ActiveEntry): void {\n if (entry.remaining <= 0) return;\n entry.startedAt = Date.now();\n entry.timer = setTimeout(() => this.dismiss(entry.id), entry.remaining);\n }\n\n private pauseTimer(entry: ActiveEntry): void {\n if (!entry.timer) return;\n clearTimeout(entry.timer);\n entry.timer = undefined;\n if (entry.startedAt) {\n entry.remaining = Math.max(0, entry.remaining - (Date.now() - entry.startedAt));\n }\n }\n\n // Host plumbing\n\n private ensureHost(position: WrToastPosition): void {\n if (this.overlayRef) {\n if (position !== this.currentPosition) this.setPosition(position);\n return;\n }\n\n this.currentPosition = position;\n\n this.overlayRef = this.overlay.create({\n positionStrategy: this.overlay.position().global(),\n scrollStrategy: this.overlay.scrollStrategies.noop(),\n hasBackdrop: false,\n panelClass: ['wr-toast-overlay'],\n });\n\n const portal = new ComponentPortal(WrToastHost);\n this.hostRef = this.overlayRef.attach(portal);\n this.hostRef.setInput('position', position);\n this.hostRef.setInput('mode', this.currentMode);\n this.hostRef.setInput('config', this.config);\n\n const inst = this.hostRef.instance;\n inst.dismissed.subscribe(id => this.dismiss(id));\n inst.dismissAllRequested.subscribe(() => this.dismissAll());\n inst.pauseRequested.subscribe(id => {\n const entry = this.active.find(t => t.id === id);\n if (entry) this.pauseTimer(entry);\n });\n inst.resumeRequested.subscribe(id => {\n const entry = this.active.find(t => t.id === id);\n if (entry) this.startTimer(entry);\n });\n }\n\n /** Fill any free stack slots from the queue (FIFO), starting each promoted\n * toast's auto-dismiss timer only as it becomes visible. */\n private promoteFromQueue(): void {\n const max = this.config.maxStack;\n while ((max <= 0 || this.active.length < max) && this.queue.length > 0) {\n const [next, ...rest] = this.queue;\n this.queue = rest;\n this.active = [...this.active, next];\n this.startTimer(next);\n }\n }\n\n private pushToHost(): void {\n this.hostRef?.instance.toasts.set([...this.active]);\n this.hostRef?.instance.queued.set(this.queue.length);\n }\n\n private disposeHost(): void {\n if (this.overlayRef) {\n this.overlayRef.dispose();\n this.overlayRef = null;\n this.hostRef = null;\n }\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';\n\nimport { DEFAULT_TOAST_CONFIG } from './default-toast-config';\nimport type { WrToastConfig } from './interfaces';\nimport { WR_TOAST_CONFIG } from './tokens';\n\n/**\n * Registers a global {@link WrToastConfig} for {@link WrToast}. Any\n * field you omit falls back to {@link DEFAULT_TOAST_CONFIG}; the `labels`\n * sub-object is merged separately so you can override a single string at a\n * time (useful for i18n).\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrToastConfig({\n * position: 'bottom-end',\n * showCopy: true,\n * maxStack: 3,\n * labels: { close: 'Закрыть' },\n * }),\n * ],\n * });\n * ```\n */\nexport function provideWrToastConfig(\n config: Partial<Omit<WrToastConfig, 'labels'>> & { readonly labels?: Partial<WrToastConfig['labels']> }\n): EnvironmentProviders {\n const merged: WrToastConfig = {\n ...DEFAULT_TOAST_CONFIG,\n ...config,\n labels: { ...DEFAULT_TOAST_CONFIG.labels, ...config.labels },\n };\n return makeEnvironmentProviders([{ provide: WR_TOAST_CONFIG, useValue: merged }]);\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,173 @@
1
+ import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+ import { WrButtonHarness } from 'ngwr/button/testing';
3
+
4
+ /**
5
+ * @license
6
+ *
7
+ * Use of this source code is governed by an MIT-style license that can be
8
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
9
+ */
10
+ /**
11
+ * Test harness for the card `WrTour` shows beside the spotlit element.
12
+ *
13
+ * `WrTour` is a service with no element of its own, so there is nothing in your
14
+ * fixture to load: the popup is a portal in the NGWR overlay container, and this
15
+ * comes from `TestbedHarnessEnvironment.documentRootLoader()`. **One card exists at
16
+ * a time** — the service tears the whole step down before opening the next — so a
17
+ * harness held across {@link next} is pointed at a detached element, and a fresh one
18
+ * has to be fetched per step.
19
+ *
20
+ * **The card is rebuilt per step, and that is what makes `getHarnessOrNull` the way
21
+ * to ask whether a tour is running.** There is no "closed" state to read: the popup,
22
+ * the overlay and the spotlight all go away together.
23
+ *
24
+ * **What "last" means here is not `current === total`.** A step whose target is not
25
+ * on the page is skipped, so a tour of three steps can show two, and the service
26
+ * looks AHEAD for a reachable one to decide what the primary button says.
27
+ * {@link getProgress} reports the printed count, {@link getPrimaryLabel} what the
28
+ * button actually reads — asserting the second is what catches a card that says
29
+ * "Next" and then ends the tour.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
34
+ * tour.start(steps);
35
+ * await fixture.whenStable();
36
+ *
37
+ * const card = await rootLoader.getHarness(WrTourHarness);
38
+ * expect(await card.getTitle()).toBe('Search');
39
+ * await card.next();
40
+ * ```
41
+ *
42
+ * @see https://ngwr.dev/guides/testing
43
+ */
44
+ class WrTourHarness extends ComponentHarness {
45
+ static hostSelector = '.wr-tour-popup';
46
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
47
+ static with(options = {}) {
48
+ return new HarnessPredicate(WrTourHarness, options)
49
+ .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title))
50
+ .addOption('content', options.content, (harness, content) => HarnessPredicate.stringMatches(harness.getContent(), content));
51
+ }
52
+ /**
53
+ * Whether this card is still on the page.
54
+ *
55
+ * For a harness you are already HOLDING: moving to another step disposes the
56
+ * overlay, so this flips to `false` where a fresh `getHarnessOrNull()` answers
57
+ * with the NEW card rather than with nothing.
58
+ */
59
+ async isShowing() {
60
+ return (await this.host()).matchesSelector('body .wr-tour-popup');
61
+ }
62
+ /** The step's heading, or `null` for a step given no `title`. */
63
+ async getTitle() {
64
+ const title = await this.locatorForOptional('.wr-tour-popup__title')();
65
+ return title ? title.text() : null;
66
+ }
67
+ /** The step's body copy. */
68
+ async getContent() {
69
+ return (await this.locatorFor('.wr-tour-popup__content')()).text();
70
+ }
71
+ /** The progress line as printed, e.g. `Step 2 of 4`. */
72
+ async getProgressText() {
73
+ return (await this.locatorFor('.wr-tour-popup__progress')()).text();
74
+ }
75
+ /**
76
+ * The two numbers out of the progress line, or `null` when it does not hold two.
77
+ *
78
+ * Parsed from the rendered string rather than asked of the service, because the
79
+ * service is not something a harness can reach — and the string is what the user
80
+ * actually gets. A catalog that spells the numbers as words, or reverses them,
81
+ * makes this `null` instead of a wrong answer; assert {@link getProgressText} in
82
+ * that case.
83
+ *
84
+ * `total` is how many steps the tour was STARTED with, not how many it will show:
85
+ * a step whose target is missing is skipped and still counted here, which is the
86
+ * component's own choice and worth knowing before writing an assertion on it.
87
+ */
88
+ async getProgress() {
89
+ const digits = (await this.getProgressText()).match(/\d+/g);
90
+ if (!digits || digits.length < 2)
91
+ return null;
92
+ return { current: Number(digits[0]), total: Number(digits[1]) };
93
+ }
94
+ /**
95
+ * The name the card announces — its title and the progress line, or just the
96
+ * progress line for an untitled step.
97
+ *
98
+ * The card is an `aria-modal` dialog, so it needs a name; the progress line is
99
+ * what an untitled step has instead of one.
100
+ */
101
+ async getAccessibleName() {
102
+ return (await this.host()).getAttribute('aria-label');
103
+ }
104
+ /** Whether the card announces itself as a modal dialog. */
105
+ async isModal() {
106
+ const host = await this.host();
107
+ return (await host.getAttribute('role')) === 'dialog' && (await host.getAttribute('aria-modal')) === 'true';
108
+ }
109
+ /**
110
+ * Whether the card offers a Back button — which is the same question as "is this
111
+ * the first step", since the button is only rendered past it.
112
+ */
113
+ async hasBack() {
114
+ return (await this.locatorForOptional('.wr-tour-popup__action--back')()) !== null;
115
+ }
116
+ /**
117
+ * What the primary button READS — the "next" label, or the "done" one on the last
118
+ * step the user will see.
119
+ *
120
+ * The assertion worth writing, and not derivable from the count: the service looks
121
+ * ahead for a step whose target is still on the page, so a tour whose last step is
122
+ * hidden ends one card early and this is the only place that shows.
123
+ */
124
+ async getPrimaryLabel() {
125
+ return (await this.primary()).getText();
126
+ }
127
+ /** The Skip button's label. */
128
+ async getSkipLabel() {
129
+ return (await this.skip()).getText();
130
+ }
131
+ /** The Back button's label. Throws on the first step, where there is none. */
132
+ async getBackLabel() {
133
+ return (await this.backButton('getBackLabel')).getText();
134
+ }
135
+ /**
136
+ * Press the primary button — the next step, or the end of the tour.
137
+ *
138
+ * Composed through {@link WrButtonHarness} rather than clicking an element: these
139
+ * are `wr-btn`s, and that harness already knows how one reports being off.
140
+ */
141
+ async next() {
142
+ await (await this.primary()).click();
143
+ }
144
+ /** Press Back. Throws on the first step, where the button is not rendered. */
145
+ async back() {
146
+ await (await this.backButton('back')).click();
147
+ }
148
+ /** Press Skip — ending the tour without finishing it. */
149
+ async skipTour() {
150
+ await (await this.skip()).click();
151
+ }
152
+ async primary() {
153
+ return this.locatorFor(WrButtonHarness.with({ selector: '.wr-tour-popup__action--next' }))();
154
+ }
155
+ async skip() {
156
+ return this.locatorFor(WrButtonHarness.with({ selector: '.wr-tour-popup__action--skip' }))();
157
+ }
158
+ async backButton(method) {
159
+ const button = await this.locatorForOptional(WrButtonHarness.with({ selector: '.wr-tour-popup__action--back' }))();
160
+ if (!button) {
161
+ throw new Error(`WrTourHarness.${method}(): this card has no Back button — the tour is on its first step, where it is ` +
162
+ 'not rendered at all.');
163
+ }
164
+ return button;
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Generated bundle index. Do not edit.
170
+ */
171
+
172
+ export { WrTourHarness };
173
+ //# sourceMappingURL=ngwr-tour-testing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngwr-tour-testing.mjs","sources":["../../../projects/lib/tour/testing/wr-tour-harness.ts","../../../projects/lib/tour/testing/ngwr-tour-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport { WrButtonHarness } from 'ngwr/button/testing';\n\nimport type { WrTourHarnessFilters, WrTourProgress } from './interfaces';\n\n/**\n * Test harness for the card `WrTour` shows beside the spotlit element.\n *\n * `WrTour` is a service with no element of its own, so there is nothing in your\n * fixture to load: the popup is a portal in the NGWR overlay container, and this\n * comes from `TestbedHarnessEnvironment.documentRootLoader()`. **One card exists at\n * a time** — the service tears the whole step down before opening the next — so a\n * harness held across {@link next} is pointed at a detached element, and a fresh one\n * has to be fetched per step.\n *\n * **The card is rebuilt per step, and that is what makes `getHarnessOrNull` the way\n * to ask whether a tour is running.** There is no \"closed\" state to read: the popup,\n * the overlay and the spotlight all go away together.\n *\n * **What \"last\" means here is not `current === total`.** A step whose target is not\n * on the page is skipped, so a tour of three steps can show two, and the service\n * looks AHEAD for a reachable one to decide what the primary button says.\n * {@link getProgress} reports the printed count, {@link getPrimaryLabel} what the\n * button actually reads — asserting the second is what catches a card that says\n * \"Next\" and then ends the tour.\n *\n * @example\n * ```ts\n * const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);\n * tour.start(steps);\n * await fixture.whenStable();\n *\n * const card = await rootLoader.getHarness(WrTourHarness);\n * expect(await card.getTitle()).toBe('Search');\n * await card.next();\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrTourHarness extends ComponentHarness {\n static hostSelector = '.wr-tour-popup';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrTourHarnessFilters = {}): HarnessPredicate<WrTourHarness> {\n return new HarnessPredicate(WrTourHarness, options)\n .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title))\n .addOption('content', options.content, (harness, content) =>\n HarnessPredicate.stringMatches(harness.getContent(), content)\n );\n }\n\n /**\n * Whether this card is still on the page.\n *\n * For a harness you are already HOLDING: moving to another step disposes the\n * overlay, so this flips to `false` where a fresh `getHarnessOrNull()` answers\n * with the NEW card rather than with nothing.\n */\n async isShowing(): Promise<boolean> {\n return (await this.host()).matchesSelector('body .wr-tour-popup');\n }\n\n /** The step's heading, or `null` for a step given no `title`. */\n async getTitle(): Promise<string | null> {\n const title = await this.locatorForOptional('.wr-tour-popup__title')();\n return title ? title.text() : null;\n }\n\n /** The step's body copy. */\n async getContent(): Promise<string> {\n return (await this.locatorFor('.wr-tour-popup__content')()).text();\n }\n\n /** The progress line as printed, e.g. `Step 2 of 4`. */\n async getProgressText(): Promise<string> {\n return (await this.locatorFor('.wr-tour-popup__progress')()).text();\n }\n\n /**\n * The two numbers out of the progress line, or `null` when it does not hold two.\n *\n * Parsed from the rendered string rather than asked of the service, because the\n * service is not something a harness can reach — and the string is what the user\n * actually gets. A catalog that spells the numbers as words, or reverses them,\n * makes this `null` instead of a wrong answer; assert {@link getProgressText} in\n * that case.\n *\n * `total` is how many steps the tour was STARTED with, not how many it will show:\n * a step whose target is missing is skipped and still counted here, which is the\n * component's own choice and worth knowing before writing an assertion on it.\n */\n async getProgress(): Promise<WrTourProgress | null> {\n const digits = (await this.getProgressText()).match(/\\d+/g);\n if (!digits || digits.length < 2) return null;\n return { current: Number(digits[0]), total: Number(digits[1]) };\n }\n\n /**\n * The name the card announces — its title and the progress line, or just the\n * progress line for an untitled step.\n *\n * The card is an `aria-modal` dialog, so it needs a name; the progress line is\n * what an untitled step has instead of one.\n */\n async getAccessibleName(): Promise<string | null> {\n return (await this.host()).getAttribute('aria-label');\n }\n\n /** Whether the card announces itself as a modal dialog. */\n async isModal(): Promise<boolean> {\n const host = await this.host();\n return (await host.getAttribute('role')) === 'dialog' && (await host.getAttribute('aria-modal')) === 'true';\n }\n\n /**\n * Whether the card offers a Back button — which is the same question as \"is this\n * the first step\", since the button is only rendered past it.\n */\n async hasBack(): Promise<boolean> {\n return (await this.locatorForOptional('.wr-tour-popup__action--back')()) !== null;\n }\n\n /**\n * What the primary button READS — the \"next\" label, or the \"done\" one on the last\n * step the user will see.\n *\n * The assertion worth writing, and not derivable from the count: the service looks\n * ahead for a step whose target is still on the page, so a tour whose last step is\n * hidden ends one card early and this is the only place that shows.\n */\n async getPrimaryLabel(): Promise<string> {\n return (await this.primary()).getText();\n }\n\n /** The Skip button's label. */\n async getSkipLabel(): Promise<string> {\n return (await this.skip()).getText();\n }\n\n /** The Back button's label. Throws on the first step, where there is none. */\n async getBackLabel(): Promise<string> {\n return (await this.backButton('getBackLabel')).getText();\n }\n\n /**\n * Press the primary button — the next step, or the end of the tour.\n *\n * Composed through {@link WrButtonHarness} rather than clicking an element: these\n * are `wr-btn`s, and that harness already knows how one reports being off.\n */\n async next(): Promise<void> {\n await (await this.primary()).click();\n }\n\n /** Press Back. Throws on the first step, where the button is not rendered. */\n async back(): Promise<void> {\n await (await this.backButton('back')).click();\n }\n\n /** Press Skip — ending the tour without finishing it. */\n async skipTour(): Promise<void> {\n await (await this.skip()).click();\n }\n\n private async primary(): Promise<WrButtonHarness> {\n return this.locatorFor(WrButtonHarness.with({ selector: '.wr-tour-popup__action--next' }))();\n }\n\n private async skip(): Promise<WrButtonHarness> {\n return this.locatorFor(WrButtonHarness.with({ selector: '.wr-tour-popup__action--skip' }))();\n }\n\n private async backButton(method: string): Promise<WrButtonHarness> {\n const button = await this.locatorForOptional(WrButtonHarness.with({ selector: '.wr-tour-popup__action--back' }))();\n if (!button) {\n throw new Error(\n `WrTourHarness.${method}(): this card has no Back button — the tour is on its first step, where it is ` +\n 'not rendered at all.'\n );\n }\n return button;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -49,11 +49,11 @@ class WrTourPopup {
49
49
  }, /* @ts-ignore */
50
50
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
51
51
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrTourPopup, deps: [], target: i0.ɵɵFactoryTarget.Component });
52
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrTourPopup, isStandalone: true, selector: "wr-tour-popup", host: { attributes: { "role": "dialog", "aria-modal": "true" }, properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "wr-tour-popup" }, ngImport: i0, template: "@let step = tour.step();\n\n<p class=\"wr-tour-popup__progress\">{{ progressText() }}</p>\n\n@if (step?.title; as title) {\n <h2 class=\"wr-tour-popup__title\">{{ title }}</h2>\n}\n\n<p class=\"wr-tour-popup__content\">{{ step?.content }}</p>\n\n<div class=\"wr-tour-popup__actions\">\n <button wr-btn type=\"button\" size=\"sm\" color=\"medium\" outlined (click)=\"tour.stop()\">\n {{ skipLabel }}\n </button>\n\n <span class=\"wr-tour-popup__spacer\"></span>\n\n @if (!isFirst()) {\n <button wr-btn type=\"button\" size=\"sm\" outlined (click)=\"tour.prev()\">{{ backLabel }}</button>\n }\n <button wr-btn type=\"button\" size=\"sm\" color=\"primary\" (click)=\"tour.next()\">\n {{ isLast() ? doneLabel : nextLabel }}\n </button>\n</div>\n", dependencies: [{ kind: "component", type: WrButton, selector: "wr-btn, button[wr-btn], a[wr-btn]", inputs: ["color", "size", "shape", "icon", "iconPosition", "disabled", "outlined", "block", "loading", "isDisabledWhenLoading"] }], encapsulation: i0.ViewEncapsulation.None });
52
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: WrTourPopup, isStandalone: true, selector: "wr-tour-popup", host: { attributes: { "role": "dialog", "aria-modal": "true" }, properties: { "attr.aria-label": "ariaLabel()" }, classAttribute: "wr-tour-popup" }, ngImport: i0, template: "@let step = tour.step();\n\n<p class=\"wr-tour-popup__progress\">{{ progressText() }}</p>\n\n@if (step?.title; as title) {\n <h2 class=\"wr-tour-popup__title\">{{ title }}</h2>\n}\n\n<p class=\"wr-tour-popup__content\">{{ step?.content }}</p>\n\n<div class=\"wr-tour-popup__actions\">\n <!-- The three buttons are told apart by a class rather than by their position in\n the row: the back button is conditional, so an index means one thing on the\n first step and another everywhere else \u2014 and the labels are translated. -->\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"medium\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--skip\"\n (click)=\"tour.stop()\"\n >\n {{ skipLabel }}\n </button>\n\n <span class=\"wr-tour-popup__spacer\"></span>\n\n @if (!isFirst()) {\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--back\"\n (click)=\"tour.prev()\"\n >\n {{ backLabel }}\n </button>\n }\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n class=\"wr-tour-popup__action wr-tour-popup__action--next\"\n (click)=\"tour.next()\"\n >\n {{ isLast() ? doneLabel : nextLabel }}\n </button>\n</div>\n", dependencies: [{ kind: "component", type: WrButton, selector: "wr-btn, button[wr-btn], a[wr-btn]", inputs: ["color", "size", "shape", "icon", "iconPosition", "disabled", "outlined", "block", "loading", "isDisabledWhenLoading"] }], encapsulation: i0.ViewEncapsulation.None });
53
53
  }
54
54
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WrTourPopup, decorators: [{
55
55
  type: Component,
56
- args: [{ selector: 'wr-tour-popup', encapsulation: ViewEncapsulation.None, host: { class: 'wr-tour-popup', role: 'dialog', 'aria-modal': 'true', '[attr.aria-label]': 'ariaLabel()' }, imports: [WrButton], template: "@let step = tour.step();\n\n<p class=\"wr-tour-popup__progress\">{{ progressText() }}</p>\n\n@if (step?.title; as title) {\n <h2 class=\"wr-tour-popup__title\">{{ title }}</h2>\n}\n\n<p class=\"wr-tour-popup__content\">{{ step?.content }}</p>\n\n<div class=\"wr-tour-popup__actions\">\n <button wr-btn type=\"button\" size=\"sm\" color=\"medium\" outlined (click)=\"tour.stop()\">\n {{ skipLabel }}\n </button>\n\n <span class=\"wr-tour-popup__spacer\"></span>\n\n @if (!isFirst()) {\n <button wr-btn type=\"button\" size=\"sm\" outlined (click)=\"tour.prev()\">{{ backLabel }}</button>\n }\n <button wr-btn type=\"button\" size=\"sm\" color=\"primary\" (click)=\"tour.next()\">\n {{ isLast() ? doneLabel : nextLabel }}\n </button>\n</div>\n" }]
56
+ args: [{ selector: 'wr-tour-popup', encapsulation: ViewEncapsulation.None, host: { class: 'wr-tour-popup', role: 'dialog', 'aria-modal': 'true', '[attr.aria-label]': 'ariaLabel()' }, imports: [WrButton], template: "@let step = tour.step();\n\n<p class=\"wr-tour-popup__progress\">{{ progressText() }}</p>\n\n@if (step?.title; as title) {\n <h2 class=\"wr-tour-popup__title\">{{ title }}</h2>\n}\n\n<p class=\"wr-tour-popup__content\">{{ step?.content }}</p>\n\n<div class=\"wr-tour-popup__actions\">\n <!-- The three buttons are told apart by a class rather than by their position in\n the row: the back button is conditional, so an index means one thing on the\n first step and another everywhere else \u2014 and the labels are translated. -->\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"medium\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--skip\"\n (click)=\"tour.stop()\"\n >\n {{ skipLabel }}\n </button>\n\n <span class=\"wr-tour-popup__spacer\"></span>\n\n @if (!isFirst()) {\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n outlined\n class=\"wr-tour-popup__action wr-tour-popup__action--back\"\n (click)=\"tour.prev()\"\n >\n {{ backLabel }}\n </button>\n }\n <button\n wr-btn\n type=\"button\"\n size=\"sm\"\n color=\"primary\"\n class=\"wr-tour-popup__action wr-tour-popup__action--next\"\n (click)=\"tour.next()\"\n >\n {{ isLast() ? doneLabel : nextLabel }}\n </button>\n</div>\n" }]
57
57
  }] });
58
58
 
59
59
  /**