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
@@ -0,0 +1,263 @@
1
+ import { BaseHarnessFilters, ContentContainerComponentHarness, HarnessPredicate, ComponentHarness } from '@angular/cdk/testing';
2
+ import { WrWindowState } from 'ngwr/window';
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
+ /** Narrows which `<wr-window>` a harness query matches. */
12
+ interface WrWindowHarnessFilters extends BaseHarnessFilters {
13
+ /** Match the title-bar text — a string is an exact match, a RegExp is tested. */
14
+ readonly title?: string | RegExp;
15
+ /** Match windows in one visual state. */
16
+ readonly state?: WrWindowState;
17
+ }
18
+ /** Narrows which `<wr-window-taskbar>` a harness query matches. */
19
+ interface WrWindowTaskbarHarnessFilters extends BaseHarnessFilters {
20
+ /** Match the edge the taskbar is pinned to. */
21
+ readonly position?: 'top' | 'bottom';
22
+ }
23
+ /**
24
+ * Where a window is and how big, in CSS pixels — the numbers the component writes
25
+ * inline, not a measured box.
26
+ */
27
+ interface WrWindowBox {
28
+ readonly x: number;
29
+ readonly y: number;
30
+ readonly width: number;
31
+ readonly height: number;
32
+ }
33
+
34
+ /**
35
+ * @license
36
+ *
37
+ * Use of this source code is governed by an MIT-style license that can be
38
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
39
+ */
40
+
41
+ /**
42
+ * Test harness for a window opened through `WrWindowManager.open()`.
43
+ *
44
+ * `WrWindow` is deliberately not exported — a window is always a service call — so
45
+ * there is nothing in your fixture to load: each window is a portal in its own
46
+ * overlay pane, and this comes from
47
+ * `TestbedHarnessEnvironment.documentRootLoader()`.
48
+ *
49
+ * It is a CONTENT CONTAINER, like `WrDialogHarness`: the component you opened is
50
+ * projected into the window's body, so `window.getHarness(WrButtonHarness…)` reads
51
+ * ITS buttons and cannot reach another window's. That matters more here than
52
+ * anywhere else, because windows are explicitly non-modal and several are normally
53
+ * open at once.
54
+ *
55
+ * **Geometry is read from the inline styles the component writes**, never measured:
56
+ * a window is positioned with `left` / `top` / `width` / `height` in pixels, and a
57
+ * unit test has no layout to measure. That also makes {@link getBox} the way to
58
+ * assert a move or a resize — including the ones a drag would produce, which no
59
+ * synthetic pointer event can, since the drag divides by a rect that is 0×0 here.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
64
+ * windows.open(EditorComponent, { title: 'Untitled.md' });
65
+ * await fixture.whenStable();
66
+ *
67
+ * const win = await rootLoader.getHarness(WrWindowHarness.with({ title: 'Untitled.md' }));
68
+ * await win.maximize();
69
+ * expect(await win.getState()).toBe('maximized');
70
+ * ```
71
+ *
72
+ * @see https://ngwr.dev/guides/testing
73
+ */
74
+ declare class WrWindowHarness extends ContentContainerComponentHarness {
75
+ static hostSelector: string;
76
+ /** Build a predicate that narrows the query — windows come in stacks. */
77
+ static with(options?: WrWindowHarnessFilters): HarnessPredicate<WrWindowHarness>;
78
+ private readonly titleEl;
79
+ /**
80
+ * Whether this window is still on the page.
81
+ *
82
+ * For a harness you are already HOLDING: closing disposes the overlay, so this
83
+ * flips to `false` where a fresh `getHarnessOrNull()` comes back `null`. A
84
+ * MINIMIZED window is still open — it is a state, not a dismissal — and this
85
+ * stays `true` for one.
86
+ */
87
+ isOpen(): Promise<boolean>;
88
+ /** The title-bar text. */
89
+ getTitle(): Promise<string>;
90
+ /** The projected `[wrWindowTitleExtra]` content, trimmed — empty when there is none. */
91
+ getTitleExtraText(): Promise<string>;
92
+ /** The window's visual state, from the host modifier. */
93
+ getState(): Promise<WrWindowState>;
94
+ /**
95
+ * The OS the chrome is dressed as — `macos`, `windows` or `linux`.
96
+ *
97
+ * Worth asserting because it is not cosmetic: on macOS the buttons are a
98
+ * traffic-light cluster in close → minimize → maximize order, and the Linux
99
+ * chrome renders neither minimize nor maximize UNLESS `showMinimize` /
100
+ * `showMaximize` asks for them. "No minimize on Linux" is a default, not an
101
+ * invariant — see {@link hasMinimizeButton}.
102
+ */
103
+ getOs(): Promise<string>;
104
+ /** The title-bar density — `normal` or `compact`. */
105
+ getChromeSize(): Promise<string>;
106
+ /**
107
+ * Where the window is and how big, in CSS pixels.
108
+ *
109
+ * From the inline styles the component writes, which is the only readable answer
110
+ * without layout — and the same numbers a drag or a snap would change.
111
+ */
112
+ getBox(): Promise<WrWindowBox>;
113
+ /**
114
+ * The window's stacking order.
115
+ *
116
+ * The manager hands out a z-index per focus, so this is how a spec asserts that
117
+ * clicking a window brought it to the front — the one thing a window manager
118
+ * exists to do, and the reason these panes are deliberately kept OUT of the
119
+ * browser's top layer, which orders strictly by entry.
120
+ */
121
+ getZIndex(): Promise<number>;
122
+ /** Whether the resize handles are rendered — `resizable`, and only in the normal state. */
123
+ isResizable(): Promise<boolean>;
124
+ /** The resize handles currently rendered, by their edge / corner suffix. */
125
+ getResizeHandles(): Promise<string[]>;
126
+ /** The body text of the window — the component you opened, as rendered. */
127
+ getBodyText(): Promise<string>;
128
+ /** The projected `[wrWindowStatusBar]` content, trimmed. */
129
+ getStatusBarText(): Promise<string>;
130
+ /** Whether the chrome offers a close button (`showClose`). */
131
+ hasCloseButton(): Promise<boolean>;
132
+ /**
133
+ * Whether the chrome offers a minimize button.
134
+ *
135
+ * `false` on Linux BY DEFAULT — that chrome is close-only by convention, which
136
+ * is a real behavioural difference and not a style. `showMinimize: true`
137
+ * overrides it, and a spec that asserts "no minimize on Linux" without saying
138
+ * which of the two it means will pass for the wrong reason.
139
+ */
140
+ hasMinimizeButton(): Promise<boolean>;
141
+ /** Whether the chrome offers a maximize button. Also `false` on Linux by default. */
142
+ hasMaximizeButton(): Promise<boolean>;
143
+ /** The close button's accessible name — the buttons are icon-only, so it is their only name. */
144
+ getCloseLabel(): Promise<string | null>;
145
+ /**
146
+ * The minimize button's accessible name, which flips to the restore wording while
147
+ * the window is minimized — the same button does both.
148
+ */
149
+ getMinimizeLabel(): Promise<string | null>;
150
+ /** The maximize button's accessible name, which flips while the window is maximized. */
151
+ getMaximizeLabel(): Promise<string | null>;
152
+ /** Click the close button. Throws on a window opened `showClose: false`. */
153
+ close(): Promise<void>;
154
+ /**
155
+ * Click the minimize button — which RESTORES a minimized window, since it is the
156
+ * same control.
157
+ */
158
+ minimize(): Promise<void>;
159
+ /** Click the maximize button — which restores a maximized window down. */
160
+ maximize(): Promise<void>;
161
+ /**
162
+ * Double-click the title bar, the other way to maximize.
163
+ *
164
+ * A separate gesture worth its own assertion, and it does NOT follow the
165
+ * button: only an explicit `showMaximize: false` turns it off. The Linux
166
+ * chrome hides the button by convention and keeps the gesture — which is also
167
+ * the only way out of a window that reached `maximized` without one.
168
+ */
169
+ doubleClickChrome(): Promise<void>;
170
+ /** Click the window body — which pulls it to the front of the stack. */
171
+ focusWindow(): Promise<void>;
172
+ /** Press Escape. A window opened `closeOnEscape: false` ignores it — assert, do not assume. */
173
+ sendEscape(): Promise<void>;
174
+ /** The role the window announces — `dialog`, on a non-modal window. */
175
+ getRole(): Promise<string | null>;
176
+ /**
177
+ * Whether the window takes its accessible name from its own title element.
178
+ *
179
+ * Resolved rather than trusted: `aria-labelledby` naming an element that is not
180
+ * this window's title is not a name, and with several windows open the ids are
181
+ * the only thing keeping them apart.
182
+ */
183
+ isLabelledByTitle(): Promise<boolean>;
184
+ /** Whether the window is hidden from assistive tech (`aria-hidden`, set while closed). */
185
+ isHiddenFromAssistiveTech(): Promise<boolean>;
186
+ private chromeAction;
187
+ private requireAction;
188
+ }
189
+
190
+ /**
191
+ * @license
192
+ *
193
+ * Use of this source code is governed by an MIT-style license that can be
194
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
195
+ */
196
+
197
+ /**
198
+ * Test harness for `<wr-window-taskbar>` — the rail of minimized windows.
199
+ *
200
+ * The taskbar IS an element in your template, so it comes from the normal fixture
201
+ * loader, unlike the windows it lists. It renders nothing but its own host until a
202
+ * window is minimized; {@link isEmpty} is the question, and {@link getTabTitles}
203
+ * answers `[]` rather than throwing, because "no minimized windows" is the ordinary
204
+ * state rather than a mistake.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * const taskbar = await loader.getHarness(WrWindowTaskbarHarness);
209
+ *
210
+ * await (await rootLoader.getHarness(WrWindowHarness)).minimize();
211
+ * expect(await taskbar.getTabTitles()).toEqual(['Untitled.md']);
212
+ * await taskbar.restore('Untitled.md');
213
+ * ```
214
+ *
215
+ * @see https://ngwr.dev/guides/testing
216
+ */
217
+ declare class WrWindowTaskbarHarness extends ComponentHarness {
218
+ static hostSelector: string;
219
+ /** Build a predicate that narrows the query. */
220
+ static with(options?: WrWindowTaskbarHarnessFilters): HarnessPredicate<WrWindowTaskbarHarness>;
221
+ /** The edge the rail is pinned to. */
222
+ getPosition(): Promise<'top' | 'bottom'>;
223
+ /**
224
+ * The rail's accessible name — it is a `role="toolbar"`, and an unnamed one is
225
+ * announced as nothing.
226
+ */
227
+ getRailLabel(): Promise<string | null>;
228
+ /** Whether nothing is minimized — the rail draws no markup at all then. */
229
+ isEmpty(): Promise<boolean>;
230
+ /**
231
+ * The titles in the rail, in order.
232
+ *
233
+ * A window opened without a title still gets a tab, named by the catalog's
234
+ * fallback rather than left blank — a nameless tab is unreachable by voice and
235
+ * indistinguishable from its neighbours.
236
+ */
237
+ getTabTitles(): Promise<string[]>;
238
+ /** A tab's accessible name — the restore wording with the window's title in it. */
239
+ getRestoreLabel(title: string): Promise<string | null>;
240
+ /** Click a tab — restoring that window and focusing it. */
241
+ restore(title: string): Promise<void>;
242
+ /**
243
+ * Click a tab's ✕ — closing the window WITHOUT restoring it.
244
+ *
245
+ * Still worth asserting separately now that the two are siblings rather than
246
+ * nested: they sit inside one pill and look like one control, so a close that
247
+ * also restored would flash a closing window's content and look plausible.
248
+ */
249
+ closeTab(title: string): Promise<void>;
250
+ /**
251
+ * The tab's BUTTON, not the pill around it.
252
+ *
253
+ * `.wr-window-taskbar__tab` is a plain container — it carries the pill's look
254
+ * and nothing else, because the close beside it cannot be a control nested in
255
+ * a control. The name and the click both belong to `__tab-restore`.
256
+ */
257
+ private requireTab;
258
+ /** Which tab carries this title — one lookup for both the tab and its close button. */
259
+ private indexOf;
260
+ }
261
+
262
+ export { WrWindowHarness, WrWindowTaskbarHarness };
263
+ export type { WrWindowBox, WrWindowHarnessFilters, WrWindowTaskbarHarnessFilters };
@@ -1,8 +1,9 @@
1
- import * as i0 from '@angular/core';
1
+ import * as _angular_core from '@angular/core';
2
2
  import { ComponentRef, WritableSignal, Signal, InjectionToken } from '@angular/core';
3
3
  import { OverlayRef } from '@angular/cdk/overlay';
4
4
  import { ReplaySubject, Subject } from 'rxjs';
5
5
  import { ComponentType } from '@angular/cdk/portal';
6
+ import * as ngwr_i18n from 'ngwr/i18n';
6
7
 
7
8
  /**
8
9
  * @license
@@ -35,8 +36,10 @@ type WrWindowChromeSize = 'compact' | 'normal';
35
36
  * - `macos` — traffic-light dots on the LEFT (red close, yellow minimize,
36
37
  * green maximize). Glyphs (×, −, +) appear when the cluster is hovered.
37
38
  * - `windows` — monochrome glyph buttons on the RIGHT.
38
- * - `linux` — close-only on the right; minimize / maximize hidden unless
39
- * explicitly requested.
39
+ * - `linux` — close-only on the right, the GNOME convention. That is a DEFAULT
40
+ * and not a rule: `showMinimize` / `showMaximize` set to `true` put the
41
+ * buttons back, which is what a Linux user needs before a window can be
42
+ * minimized into `<wr-window-taskbar>`.
40
43
  */
41
44
  type WrWindowOs = 'auto' | 'macos' | 'windows' | 'linux';
42
45
 
@@ -129,8 +132,16 @@ interface WrWindowConfig<D = unknown> {
129
132
  readonly closeOnEscape?: boolean;
130
133
  /** Snap-on-drag mode. @default 'none' */
131
134
  readonly snap?: WrWindowSnap;
135
+ /**
136
+ * Show the minimize control. Omit to follow the chrome — every OS but Linux
137
+ * shows it, and the Linux preset is close-only by convention. Pass `true` to
138
+ * override that, which is what a Linux user needs before a window can reach
139
+ * `<wr-window-taskbar>`.
140
+ */
132
141
  readonly showMinimize?: boolean;
142
+ /** Show the maximize control. Omit to follow the chrome, as with {@link showMinimize}. */
133
143
  readonly showMaximize?: boolean;
144
+ /** Show the close control. Every chrome closes, so this is not per-OS. */
134
145
  readonly showClose?: boolean;
135
146
  /** Show in `<wr-window-taskbar>` when minimized. @default true */
136
147
  readonly taskbar?: boolean;
@@ -420,8 +431,8 @@ declare class WrWindowManager {
420
431
  private applyRestore;
421
432
  /** Drop a saved workspace. */
422
433
  clearLayout(name: string): void;
423
- static ɵfac: i0.ɵɵFactoryDeclaration<WrWindowManager, never>;
424
- static ɵprov: i0.ɵɵInjectableDeclaration<WrWindowManager>;
434
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrWindowManager, never>;
435
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<WrWindowManager>;
425
436
  }
426
437
 
427
438
  /**
@@ -442,16 +453,22 @@ declare class WrWindowManager {
442
453
  * @see https://ngwr.dev/reference/components/window
443
454
  */
444
455
  declare class WrWindowTaskbar {
456
+ /** @internal */ protected readonly railLabel: _angular_core.Signal<string>;
457
+ /** @internal */ protected readonly closeLabel: _angular_core.Signal<string>;
458
+ /** @internal */ protected readonly untitled: _angular_core.Signal<string>;
459
+ /** @internal */ protected readonly restoreLabel: (params?: ngwr_i18n.WrI18nParams) => string;
445
460
  /** Edge the taskbar pins itself to. @default 'bottom' */
446
- readonly position: i0.InputSignal<"top" | "bottom">;
461
+ readonly position: _angular_core.InputSignal<"top" | "bottom">;
447
462
  private readonly manager;
448
463
  /** @internal — minimized windows that haven't opted out via `taskbar: false`. */
449
- protected readonly items: i0.Signal<WrWindowRef<unknown, unknown>[]>;
450
- protected readonly classes: i0.Signal<string>;
464
+ protected readonly items: _angular_core.Signal<WrWindowRef<unknown, unknown>[]>;
465
+ protected readonly classes: _angular_core.Signal<string>;
466
+ /** A window with no title still needs a name in the rail. */
467
+ protected tabTitle(ref: WrWindowRef<unknown, unknown>): string;
451
468
  protected restore(ref: WrWindowRef<unknown, unknown>): void;
452
469
  protected close(ref: WrWindowRef<unknown, unknown>, event: Event): void;
453
- static ɵfac: i0.ɵɵFactoryDeclaration<WrWindowTaskbar, never>;
454
- static ɵcmp: i0.ɵɵComponentDeclaration<WrWindowTaskbar, "wr-window-taskbar", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
470
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrWindowTaskbar, never>;
471
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrWindowTaskbar, "wr-window-taskbar", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
455
472
  }
456
473
 
457
474
  export { WR_WINDOW_DATA, WR_WINDOW_REF, WrWindowManager, WrWindowRef, WrWindowTaskbar };
@@ -197,8 +197,9 @@
197
197
 
198
198
  // OS preset: Linux (GNOME-style) — chrome-action retains the windows
199
199
  // look but the chrome bar is slightly taller and the
200
- // title stays left-aligned (close-only is enforced by
201
- // the template).
200
+ // title stays left-aligned. Close-only is the template's
201
+ // DEFAULT here, not a rule: `[showMinimize]="true"` puts
202
+ // the button back.
202
203
  &--os-linux {
203
204
  .wr-window__chrome {
204
205
  height: 2.5rem;
@@ -384,30 +385,45 @@
384
385
  pointer-events: auto;
385
386
  }
386
387
 
388
+ // The pill, which is now a container rather than the button itself — the
389
+ // close beside it has to be a sibling, not a control nested in a control.
390
+ // The class stays: consumers style against it, and it still names the pill.
387
391
  &__tab {
388
- appearance: none;
389
- background: transparent;
390
- border: 0;
391
392
  display: inline-flex;
392
393
  align-items: center;
393
- gap: 0.375rem;
394
- padding-block: 0.25rem;
395
- // Roomy where the title starts, tight against the trailing close button.
396
- padding-inline: 0.75rem 0.5rem;
394
+ gap: 0.125rem;
395
+ // Roomy where the title starts, tight against the trailing close button,
396
+ // which now carries its own padding to reach a 24px target.
397
+ padding-inline: 0.75rem 0.125rem;
397
398
  border-radius: var(--wr-border-radius-sm);
398
399
  color: var(--wr-color-on-surface);
399
- font-family: inherit;
400
400
  font-size: var(--wr-text-sm);
401
401
  line-height: 1.25rem;
402
- cursor: pointer;
403
402
  max-width: 12rem;
404
- transition:
405
- background var(--wr-transition-base),
406
- color var(--wr-transition-base);
403
+ transition: background var(--wr-transition-base);
407
404
 
408
405
  &:hover {
409
406
  background: rgba(var(--wr-color-outline-rgb), 0.6);
410
407
  }
408
+ }
409
+
410
+ &__tab-restore {
411
+ appearance: none;
412
+ background: transparent;
413
+ border: 0;
414
+ padding-block: 0.25rem;
415
+ padding-inline: 0;
416
+ flex: 1 1 auto;
417
+ min-width: 0;
418
+ display: inline-flex;
419
+ align-items: center;
420
+ border-radius: var(--wr-border-radius-sm);
421
+ color: inherit;
422
+ font-family: inherit;
423
+ font-size: inherit;
424
+ line-height: inherit;
425
+ cursor: pointer;
426
+ text-align: start;
411
427
 
412
428
  &:focus-visible {
413
429
  @include theme.focus-ring;
@@ -424,9 +440,16 @@
424
440
  }
425
441
 
426
442
  &__tab-close {
443
+ appearance: none;
444
+ border: 0;
445
+ background: transparent;
427
446
  flex: 0 0 auto;
428
- width: 1rem;
429
- height: 1rem;
447
+ // 24px, which is what WCAG 2.5.8 asks of a pointer target. The glyph is
448
+ // still 9px and the pill is 28px tall, so the box grows into padding that
449
+ // was already there rather than changing the taskbar's height.
450
+ width: 1.5rem;
451
+ height: 1.5rem;
452
+ padding: 0;
430
453
  display: inline-flex;
431
454
  align-items: center;
432
455
  justify-content: center;
@@ -438,6 +461,11 @@
438
461
  color: var(--wr-color-surface);
439
462
  background: var(--wr-color-danger);
440
463
  }
464
+
465
+ &:focus-visible {
466
+ @include theme.focus-ring;
467
+ outline-offset: -2px;
468
+ }
441
469
  }
442
470
  }
443
471