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,73 @@
1
+ # Setting up ngwr
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ ng add ngwr
7
+ ```
8
+
9
+ Prompts for styles, date adapter, density and theme, installs the peers, and
10
+ prints a bootstrap snippet tailored to the answers.
11
+
12
+ ## Bootstrap
13
+
14
+ ```ts
15
+ import { provideWrTheme } from 'ngwr/theme';
16
+ import { provideWrOverlay } from 'ngwr/overlay';
17
+ import { provideWrIcons } from 'ngwr/icon';
18
+ import { lucideIcons } from 'ngwr/icon/adapters/lucide';
19
+
20
+ bootstrapApplication(App, {
21
+ providers: [
22
+ provideZonelessChangeDetection(),
23
+ provideWrTheme(),
24
+ provideWrOverlay(),
25
+ provideWrIcons(lucideIcons({ check, chevronDown })),
26
+ ],
27
+ });
28
+ ```
29
+
30
+ `provideWrOverlay()` gives ngwr its OWN CDK overlay container, which is what
31
+ keeps it from colliding with Material or NG-ZORRO in the same app. It also
32
+ installs `WrVisualViewport`, which publishes `--wr-keyboard-inset`.
33
+
34
+ ## Styles
35
+
36
+ ```scss
37
+ @use 'ngwr'; // everything
38
+ @use 'ngwr/button'; // or one entry point at a time
39
+ ```
40
+
41
+ Resolved through the `sass` condition in the package's `exports` map. Entry
42
+ points that ship no stylesheet (the `/testing` harnesses, `ngwr/utils`) have no
43
+ `@use` target — importing one fails the build.
44
+
45
+ ## Providers with no default
46
+
47
+ ### `provideWrOverlay() // from 'ngwr/overlay'`
48
+
49
+ Overlays render into an ngwr-owned container; without it they never appear. Needed by `WrDialog`, `WrDrawer`, `WrToast`, `WrPopover`, `WrPopconfirm`, `WrContextMenu`, `WrSelect`, `WrDropdown`, `WrCommandPalette`, `WrCascader`, `WrMention`, `WrDatePicker`, `WrTour`, `WrLightbox`.
50
+
51
+ ### `provideWrIcons(lucideIcons({ … })) // from 'ngwr/icon' + 'ngwr/icon/adapters/lucide'`
52
+
53
+ Icons resolve by name from a registry you populate. Needed by `WrIcon`.
54
+
55
+ ### `provideWrDateAdapter(wrDateFnsAdapter) // from 'ngwr/date-adapter-fns'`
56
+
57
+ Every date mode goes through an adapter; there is no built-in default. Needed by `WrDatePicker`, `WrCalendar`, `WrEventCalendar`.
58
+
59
+ ### `provideWrI18n() + provideWrI18nStaticLoader({ en: wrEn }) // from 'ngwr/i18n'`
60
+
61
+ The pipe and directive read from a catalog you provide. Needed by `WrT`, `WrI18n`.
62
+
63
+ ## Optional, app-wide
64
+
65
+ - `provideWrConfig({ button: { size: 'sm' } })` — component defaults. A bound
66
+ value always wins, including a bound `false` over a configured `true`.
67
+ - `provideWrDensity('sm' | 'md' | 'lg' | 'touch')` — one control size for the
68
+ whole app; `touch` enlarges every hit area at once.
69
+ - `provideWrResponsiveOverlays()` — overlays present as bottom sheets under the
70
+ breakpoint (640px by default). Per-component opt-out with `[responsive]="false"`.
71
+ - `provideWrFormErrors({ … })` — one place for validation copy; `<wr-form-field>`
72
+ resolves a message per error key through it, then the i18n catalog, then a
73
+ built-in fallback.
@@ -45,8 +45,17 @@
45
45
  }
46
46
  }
47
47
 
48
+ // A column, because the connector is a SIBLING of the button inside the `<li>`:
49
+ // in a row it lands to the right of the label, where nothing connects. The
50
+ // giveaway was already in the connector's own rule — a `margin-left` of half
51
+ // the indicator only means anything when the line runs beneath the circle.
52
+ // `flex-start` rather than `stretch`: in a column that is the horizontal axis,
53
+ // so stretch would pull the button to full width and unstick the label from its
54
+ // circle. `gap: 0` because the base rule's 0.75rem would break the line.
48
55
  &--vertical &__header {
49
- align-items: stretch;
56
+ flex-direction: column;
57
+ align-items: flex-start;
58
+ gap: 0;
50
59
  flex: 0 0 auto;
51
60
  }
52
61
 
@@ -141,6 +150,10 @@
141
150
 
142
151
  &--vertical &__connector {
143
152
  width: 1.5px;
153
+ // The shared rule's `min-width: 1rem` is a minimum LENGTH for the horizontal
154
+ // line, and it outranks `width` — so without this reset the vertical connector
155
+ // paints as a 16px block instead of a 1.5px thread.
156
+ min-width: 0;
144
157
  min-height: 1.25rem;
145
158
  height: auto;
146
159
  margin: 0.25rem 0 0.25rem calc(var(--wr-stepper-indicator-size) / 2);
@@ -167,12 +180,15 @@
167
180
  }
168
181
 
169
182
  .wr-stepper--responsive:not(.wr-stepper--vertical) .wr-stepper__header {
170
- align-items: stretch;
183
+ flex-direction: column;
184
+ align-items: flex-start;
185
+ gap: 0;
171
186
  flex: 0 0 auto;
172
187
  }
173
188
 
174
189
  .wr-stepper--responsive:not(.wr-stepper--vertical) .wr-stepper__connector {
175
190
  width: 1.5px;
191
+ min-width: 0;
176
192
  min-height: 1.25rem;
177
193
  height: auto;
178
194
  margin: 0.25rem 0 0.25rem calc(var(--wr-stepper-indicator-size) / 2);
@@ -824,7 +824,9 @@
824
824
  border: 0;
825
825
  padding: 0.375rem 0.5rem;
826
826
  border-radius: var(--wr-border-radius-sm);
827
- color: var(--wr-color-primary);
827
+ // A real "Reset" text button, so `-ink`. The sort / filter GLYPHS above keep
828
+ // the bare intent: graphics are held to 3:1, which they clear.
829
+ color: var(--wr-color-primary-ink);
828
830
  font: inherit;
829
831
  font-size: var(--wr-text-sm);
830
832
  cursor: pointer;
@@ -272,9 +272,22 @@ $contrast-light: #ffffff !default;
272
272
  // 4.42. Half a point of headroom absorbs that, for 2–7 points of share.
273
273
  //
274
274
  // Going further is not free: 5.25 costs 7–11 points and 5.5 up to 14, which
275
- // on `primary` means 93% -> 79% and a visibly muddier blue.
275
+ // on `primary` meant 93% -> 79% and a visibly muddier blue. (That trade was
276
+ // priced on the PRE-v11 bases; moving a base reprices it, as `primary` below
277
+ // shows — 78% now buys 5.0, not 5.5.)
278
+ //
279
+ // `primary` was re-derived when the DARK base deepened to #3567ff so its label
280
+ // could go white: a deeper base makes the ink deeper too, which on a dark tint
281
+ // is the losing direction. axe measured the old 86% at 4.48:1 on the sidebar's
282
+ // own tint — under AA, never mind the target. 78% is the most saturated share
283
+ // that reaches 5.0 there (5.04), and it only helps the light theme, where a
284
+ // lower share means MORE `--wr-color-dark` and a deeper ink on a pale tint.
285
+ // Solved against the exact pair axe resolved on the page (#4e79fd on #0f1a36),
286
+ // because a hand-rolled composite of the tint over the canvas does not
287
+ // reproduce what the browser paints — this file's own numbers are arithmetic,
288
+ // and `pnpm check:contrast` is the authority.
276
289
  $ink-mix: (
277
- primary: 86%,
290
+ primary: 78%,
278
291
  secondary: 75%,
279
292
  success: 67%,
280
293
  warning: 48%,
@@ -124,18 +124,30 @@ $_dark: #e6ebf3;
124
124
  --wr-color-muted-text-rgb: 154, 166, 184;
125
125
 
126
126
  // Brand-color retune
127
- // The default primary (#3969e2) reads a touch dim on the deep
128
- // canvas. Bump the base + shade derivations so hover / focus rings
129
- // stay visible against slate-900.
130
- --wr-color-primary: #5b85ff;
131
- // Same reason as the loop above — the light primary pairs with white, but the
132
- // lightened dark-theme primary only reaches 3.36:1 against it.
133
- --wr-color-primary-contrast: #{colors.contrast(#5b85ff)};
134
- --wr-color-primary-rgb: 91, 133, 255;
135
- --wr-color-primary-light: #7a9eff;
136
- --wr-color-primary-dark: #2f56c9;
137
- --wr-color-primary-lighter: #99b6ff;
138
- --wr-color-primary-darker: #1f3a99;
127
+ // The default primary (#3969e2) reads a touch dim on the deep canvas. What
128
+ // carries here is SATURATION, not lightness: #3567ff is only ~7% more luminous
129
+ // than the light base but runs the blue channel to 255, and the shades follow it
130
+ // so hover / focus rings stay visible against slate-900.
131
+ //
132
+ // Deep enough for a WHITE label, and no deeper. `_contrast()` takes whichever
133
+ // of black / white scores higher, and the two are equal at √21 ≈ 4.58 — the
134
+ // previous #5b85ff sat at white 3.36 / black 6.24, so it took a BLACK label
135
+ // while the light theme's primary took white: one intent labelled two
136
+ // different ways across the themes. #3567ff reads white 4.63 / black 4.54.
137
+ //
138
+ // Saturation stays at 100%. Scaling the channels toward black reaches the same
139
+ // ratio at #4c6fd6, but that is S 63% — duller, which is the opposite of what
140
+ // this block exists for. Dropping lightness at full saturation keeps the colour
141
+ // vivid, and keeps it distinct from the light theme's #3969e2 rather than
142
+ // collapsing onto it.
143
+ --wr-color-primary: #3567ff;
144
+ --wr-color-primary-contrast: #{colors.contrast(#3567ff)};
145
+ --wr-color-primary-rgb: 53, 103, 255;
146
+ // The same lightness steps as before, taken off the new base.
147
+ --wr-color-primary-light: #547eff;
148
+ --wr-color-primary-dark: #2848aa;
149
+ --wr-color-primary-lighter: #7396ff;
150
+ --wr-color-primary-darker: #183179;
139
151
 
140
152
  // success / warning / danger — retuned bases now get the FULL symmetric
141
153
  // shade set in dark too (generated, so no intent can silently drift).
@@ -34,7 +34,8 @@
34
34
 
35
35
  &--selected {
36
36
  background: var(--wr-color-primary-soft);
37
- color: var(--wr-color-primary);
37
+ // Text on the `-soft` tint: `-ink`. Bare measured 4.19:1 light / 3.63:1 dark.
38
+ color: var(--wr-color-primary-ink);
38
39
  }
39
40
 
40
41
  // Visible ring only when the row truly has keyboard focus — not
@@ -248,7 +249,8 @@
248
249
  padding-inline: 0.5rem 0.25rem;
249
250
  border-radius: 999px;
250
251
  background: var(--wr-color-primary-soft);
251
- color: var(--wr-color-primary);
252
+ // The chip wraps a label, so this paints text on the chip's own tint.
253
+ color: var(--wr-color-primary-ink);
252
254
  font-size: var(--wr-text-sm);
253
255
  line-height: 1.4;
254
256
  user-select: none;
@@ -0,0 +1,260 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+ import { WrActionSheetAction } from 'ngwr/action-sheet';
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 open `<wr-action-sheet>` a harness query matches. */
12
+ interface WrActionSheetHarnessFilters extends BaseHarnessFilters {
13
+ /**
14
+ * Match the sheet's VISIBLE heading — a string is an exact match, a RegExp is
15
+ * tested. A sheet with no `title` has none and matches nothing here; filter on
16
+ * `accessibleName` to reach one by the name it announces instead.
17
+ */
18
+ readonly title?: string | RegExp;
19
+ /** Match the muted sub-heading under the title. */
20
+ readonly message?: string | RegExp;
21
+ /**
22
+ * Match the name the dialog announces — the visible title when there is one, and
23
+ * otherwise the screen-reader-only fallback, which is the only name an untitled
24
+ * sheet has.
25
+ */
26
+ readonly accessibleName?: string | RegExp;
27
+ }
28
+ /** Narrows which row inside an action sheet a harness query matches. */
29
+ interface WrActionSheetActionHarnessFilters extends BaseHarnessFilters {
30
+ /** Match the row's label — a string is an exact match, a RegExp is tested. */
31
+ readonly label?: string | RegExp;
32
+ /**
33
+ * Match the row's visual role. `default` covers every row the caller left
34
+ * unroled, which is what the component itself does with the value.
35
+ */
36
+ readonly role?: NonNullable<WrActionSheetAction['role']>;
37
+ /** Match only enabled (`false`) or only disabled (`true`) rows. */
38
+ readonly disabled?: boolean;
39
+ }
40
+
41
+ /**
42
+ * @license
43
+ *
44
+ * Use of this source code is governed by an MIT-style license that can be
45
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
46
+ */
47
+
48
+ /**
49
+ * Test harness for one row inside a {@link WrActionSheetHarness}.
50
+ *
51
+ * A row is a real `<button>`, not an ARIA-decorated div, so `disabled` is the
52
+ * property rather than an attribute and the CDK refuses to click it — which is the
53
+ * behaviour a spec wants asserted, since the component ALSO checks `disabled`
54
+ * inside its own handler. Either guard alone would keep a disabled row inert; both
55
+ * being there means removing one is invisible until the other is removed too, and
56
+ * {@link click} is where that shows up.
57
+ *
58
+ * **Clicking a row closes the sheet.** The component emits `action` and clears
59
+ * `open` in the same call, so a harness held across a {@link click} is pointed at a
60
+ * detached element the moment it returns — read what you need first, and get a
61
+ * fresh harness afterwards if the sheet was reopened.
62
+ *
63
+ * @see https://ngwr.dev/guides/testing
64
+ */
65
+ declare class WrActionSheetActionHarness extends ComponentHarness {
66
+ /** The class every row carries, cancel rows included. */
67
+ static hostSelector: string;
68
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
69
+ static with(options?: WrActionSheetActionHarnessFilters): HarnessPredicate<WrActionSheetActionHarness>;
70
+ /**
71
+ * The row's label, trimmed.
72
+ *
73
+ * Read from `.wr-action-sheet__label` rather than from the button, so a leading
74
+ * icon can never join it. The icon contributes no text today — it is an `<svg>` —
75
+ * but an icon set that ships a `<title>` for its own accessibility would, and the
76
+ * label element is the thing that actually holds the string.
77
+ */
78
+ getLabel(): Promise<string>;
79
+ /**
80
+ * The row's visual role, as the component painted it.
81
+ *
82
+ * `default` is returned for a row the caller left unroled, which is what the
83
+ * component does with the value: only `destructive` and `cancel` change anything,
84
+ * and everything else falls through to the plain row. The two modifiers are
85
+ * mutually exclusive by construction — `cancel` rows are filtered into their own
86
+ * group before the destructive class is ever considered — so reading them in
87
+ * either order gives the same answer.
88
+ */
89
+ getRole(): Promise<NonNullable<WrActionSheetAction['role']>>;
90
+ /**
91
+ * Whether the row refuses interaction, from the button's own `disabled` property
92
+ * — the thing the CDK consults before dispatching a click, and the DOM before
93
+ * delivering one.
94
+ *
95
+ * There is no `aria-disabled` to fall back to here, and none is wanted: the row is
96
+ * a native button, where the property already carries the state to assistive tech.
97
+ */
98
+ isDisabled(): Promise<boolean>;
99
+ /** Whether the row draws a leading icon. */
100
+ hasIcon(): Promise<boolean>;
101
+ /**
102
+ * The icon's registered name, or `null` on a row without one.
103
+ *
104
+ * From `wr-icon`'s reflected `data-icon`, which is the only place the name reaches
105
+ * the DOM — the rendered `<svg>` carries no trace of which entry of the set it
106
+ * came from.
107
+ */
108
+ getIconName(): Promise<string | null>;
109
+ /**
110
+ * Pick this row — emitting `action` and closing the sheet.
111
+ *
112
+ * Throws on a disabled row instead of quietly doing nothing. The click would not
113
+ * land anyway (the DOM swallows it), so the alternative is a spec that reads as
114
+ * "picked the row" and asserts a sheet that never moved.
115
+ */
116
+ click(): Promise<void>;
117
+ /** Move keyboard focus to the row. */
118
+ focus(): Promise<void>;
119
+ /** Whether the row currently holds focus. */
120
+ isFocused(): Promise<boolean>;
121
+ }
122
+
123
+ /**
124
+ * @license
125
+ *
126
+ * Use of this source code is governed by an MIT-style license that can be
127
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
128
+ */
129
+
130
+ /**
131
+ * Test harness for an open `<wr-action-sheet>` — the iOS-style bottom sheet of
132
+ * choices.
133
+ *
134
+ * The sheet renders through `<wr-drawer>`, so its rows are in the NGWR overlay
135
+ * container rather than in the fixture: load this from
136
+ * `TestbedHarnessEnvironment.documentRootLoader()`. A fixture-scoped loader finds
137
+ * nothing at all — the `<wr-action-sheet>` host element itself holds no content and
138
+ * the drawer it wraps is `display: none`.
139
+ *
140
+ * The anchor is `.wr-action-sheet`, the sheet's own root inside the drawer panel,
141
+ * which makes each instance self-scoping: two sheets open at once are two hosts, and
142
+ * every query here descends from one of them. That is worth stating because it is
143
+ * NOT how the drawer harness underneath has to work — a drawer publishes no link to
144
+ * the overlay it opened, so `WrDrawerHarness` anchors on the shared pane and scopes
145
+ * by id.
146
+ *
147
+ * **What belongs to the drawer, not here.** Dismissal by backdrop click or by the ✕
148
+ * button, the modal role, the focus trap and the panel's position are all the
149
+ * drawer's surface, and `WrDrawerHarness` from the same root loader answers them.
150
+ * {@link sendEscape} is the one exception, kept because dismissing without choosing
151
+ * is a documented behaviour of the sheet itself: it closes and emits NOTHING, which
152
+ * is the assertion most specs are actually after.
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * const rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
157
+ * const sheet = await rootLoader.getHarness(WrActionSheetHarness);
158
+ *
159
+ * expect(await sheet.getActionLabels()).toEqual(['Take Photo', 'Delete', 'Cancel']);
160
+ * await sheet.select({ label: 'Delete' });
161
+ * ```
162
+ *
163
+ * @see https://ngwr.dev/guides/testing
164
+ */
165
+ declare class WrActionSheetHarness extends ComponentHarness {
166
+ /** The sheet's root inside the drawer panel. A closed sheet renders none. */
167
+ static hostSelector: string;
168
+ /** Build a predicate that narrows the query — sheets can be stacked. */
169
+ static with(options?: WrActionSheetHarnessFilters): HarnessPredicate<WrActionSheetHarness>;
170
+ /**
171
+ * Whether this sheet is still open.
172
+ *
173
+ * A harness can only be obtained while the sheet is open — closing disposes the
174
+ * overlay and everything in it — so this is the answer for a harness you are
175
+ * already HOLDING: it flips to `false` after a pick or a dismissal, where a fresh
176
+ * `getHarnessOrNull()` comes back `null`.
177
+ *
178
+ * Attachment is the test rather than a class, because disposal removes the element
179
+ * without changing anything on it.
180
+ */
181
+ isOpen(): Promise<boolean>;
182
+ /** The visible heading, or `null` when the sheet was opened without a `title`. */
183
+ getTitle(): Promise<string | null>;
184
+ /** The muted sub-heading, or `null` when the sheet has no `message`. */
185
+ getMessage(): Promise<string | null>;
186
+ /**
187
+ * The name the dialog announces.
188
+ *
189
+ * The sheet always publishes one, and for an untitled sheet it is INVISIBLE: the
190
+ * component renders a screen-reader-only `[wrDrawerTitle]` carrying
191
+ * `actionSheet.label` (English default `Actions`), because a bottom sheet is an
192
+ * `aria-modal` dialog and an unnamed one is announced as nothing at all. Nothing
193
+ * on screen changes when that string is wrong or missing, which is exactly why it
194
+ * is worth an assertion.
195
+ *
196
+ * Read from `.wr-drawer__title` — the class the title directive applies — so the
197
+ * one query answers for both shapes: the visible heading carries it too.
198
+ */
199
+ getAccessibleName(): Promise<string>;
200
+ /** Whether the announced name comes from a visible heading rather than the fallback. */
201
+ isTitleVisible(): Promise<boolean>;
202
+ /**
203
+ * Whether the dialog is actually WIRED to that name — the drawer panel's
204
+ * `aria-labelledby` resolving to this sheet's own title element, and to nothing
205
+ * else on the page.
206
+ *
207
+ * {@link getAccessibleName} only proves a string exists in the markup; a screen
208
+ * reader reads it only if the reference points at it. The two are separate
209
+ * failures and the second is silent: the title renders, the sheet looks right, and
210
+ * the dialog is announced as unnamed. Worth its own assertion because the drawer
211
+ * resolves the reference AFTER attaching the panel rather than while rendering it,
212
+ * so a title that arrives late is named late or not at all.
213
+ *
214
+ * Counted across the document as well, because two panels answering to one id hand
215
+ * every reference to whichever comes first — which is how a second sheet ends up
216
+ * announcing the first one's title.
217
+ */
218
+ isNamed(): Promise<boolean>;
219
+ /** The rows this sheet offers, in DOM order — cancel rows last, in their own group. */
220
+ getActions(filters?: WrActionSheetActionHarnessFilters): Promise<WrActionSheetActionHarness[]>;
221
+ /** The labels of every row, in DOM order. */
222
+ getActionLabels(): Promise<string[]>;
223
+ /**
224
+ * The labels grouped the way the sheet lays them out: the main group first, then
225
+ * the cancel group when there is one.
226
+ *
227
+ * The grouping is the component's whole visual contract — a `cancel` row is pulled
228
+ * out of the list and pinned to the bottom with a gap above it — and it is
229
+ * invisible to {@link getActionLabels}, which flattens the two. A cancel row that
230
+ * stopped being separated would still come last in DOM order, so the flat list
231
+ * cannot catch it.
232
+ */
233
+ getActionGroups(): Promise<string[][]>;
234
+ /**
235
+ * Whether the sheet drew a separate bottom group — true exactly when at least one
236
+ * row was given `role: 'cancel'`, since the component omits the group entirely
237
+ * rather than rendering an empty one.
238
+ */
239
+ hasCancelGroup(): Promise<boolean>;
240
+ /**
241
+ * Pick the first row matching the filters.
242
+ *
243
+ * Throws when nothing matches, naming what the sheet does offer — the alternative
244
+ * is a silent no-op followed by an assertion about a sheet that never moved. A
245
+ * disabled match throws too, from the row harness.
246
+ */
247
+ select(filters: WrActionSheetActionHarnessFilters): Promise<void>;
248
+ /**
249
+ * Press Escape — dismissing the sheet WITHOUT emitting `action`.
250
+ *
251
+ * The key never needs to reach the sheet itself: the drawer underneath listens
252
+ * through the CDK's keyboard dispatcher, which keeps one document listener and
253
+ * hands the event to the top-most overlay. So with sheets stacked this dismisses
254
+ * the top one whichever harness it is called on.
255
+ */
256
+ sendEscape(): Promise<void>;
257
+ }
258
+
259
+ export { WrActionSheetActionHarness, WrActionSheetHarness };
260
+ export type { WrActionSheetActionHarnessFilters, WrActionSheetHarnessFilters };
@@ -0,0 +1,77 @@
1
+ import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
2
+
3
+ /**
4
+ * @license
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
8
+ */
9
+
10
+ /** Narrows which `<wr-bar-chart>` a harness query matches. */
11
+ interface WrBarChartHarnessFilters extends BaseHarnessFilters {
12
+ /** Match a chart holding a bar with this label. */
13
+ readonly barLabel?: string | RegExp;
14
+ }
15
+ /** One column, as the chart draws and announces it. */
16
+ interface WrBarChartBar {
17
+ /** The label printed under the column — decoration, and `aria-hidden`. */
18
+ readonly label: string;
19
+ /** The value printed above it, or `null` when `showValues` is off. */
20
+ readonly value: string | null;
21
+ /** What the column announces: the label and the value in one string. */
22
+ readonly name: string | null;
23
+ /** The bar's height as a percentage of the chart's maximum. */
24
+ readonly heightPercent: number;
25
+ }
26
+
27
+ /**
28
+ * @license
29
+ *
30
+ * Use of this source code is governed by an MIT-style license that can be
31
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
32
+ */
33
+
34
+ /**
35
+ * Test harness for `<wr-bar-chart>`.
36
+ *
37
+ * **The bars are read as PERCENTAGES, not as pixels.** Each column's height is
38
+ * written inline as a share of the chart's maximum, which is the one number that
39
+ * survives a test with no layout — and it is also the component's whole job, since
40
+ * the maximum is either given or derived from the data.
41
+ *
42
+ * **The visible label row is decoration.** Every column carries `role="img"` with
43
+ * the label AND the value in its name, and the printed labels underneath are
44
+ * `aria-hidden` — so {@link WrBarChartBar.name} is what a screen reader gets and
45
+ * {@link WrBarChartBar.label} is what is drawn. Asserting only the second would pass
46
+ * on a chart that announces nothing.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * const chart = await loader.getHarness(WrBarChartHarness);
51
+ *
52
+ * expect(await chart.getLabels()).toEqual(['Mon', 'Tue', 'Wed']);
53
+ * expect((await chart.getBars())[1].heightPercent).toBe(100);
54
+ * ```
55
+ *
56
+ * @see https://ngwr.dev/guides/testing
57
+ */
58
+ declare class WrBarChartHarness extends ComponentHarness {
59
+ static hostSelector: string;
60
+ /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */
61
+ static with(options?: WrBarChartHarnessFilters): HarnessPredicate<WrBarChartHarness>;
62
+ /** Every column, in data order. */
63
+ getBars(): Promise<WrBarChartBar[]>;
64
+ /** The labels printed under the columns, in order. */
65
+ getLabels(): Promise<string[]>;
66
+ /** What each column announces — the label and the value together. */
67
+ getAccessibleNames(): Promise<(string | null)[]>;
68
+ /** How many columns the chart drew. */
69
+ getBarCount(): Promise<number>;
70
+ /** Whether the values are printed above the bars (`showValues`). */
71
+ hasValues(): Promise<boolean>;
72
+ /** The plot's height in pixels, as the component writes it inline. */
73
+ getPlotHeight(): Promise<number>;
74
+ }
75
+
76
+ export { WrBarChartHarness };
77
+ export type { WrBarChartBar, WrBarChartHarnessFilters };