ngwr 9.1.0 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/README.md +23 -8
  2. package/action-sheet/styles/_index.scss +6 -1
  3. package/badge/styles/_index.scss +17 -7
  4. package/badge/styles/_tag.scss +12 -3
  5. package/border-glow/styles/_index.scss +5 -0
  6. package/button/styles/_index.scss +48 -1
  7. package/calendar/styles/_index.scss +9 -1
  8. package/circular-text/styles/_index.scss +6 -1
  9. package/density/styles/_index.scss +3 -1
  10. package/dialog/styles/_index.scss +66 -2
  11. package/drag-drop/styles/_index.scss +20 -7
  12. package/drawer/styles/_index.scss +61 -1
  13. package/event-calendar/styles/_index.scss +284 -0
  14. package/falling-text/styles/_index.scss +5 -0
  15. package/fesm2022/ngwr-action-sheet.mjs +1 -1
  16. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  17. package/fesm2022/ngwr-alert.mjs +8 -3
  18. package/fesm2022/ngwr-alert.mjs.map +1 -1
  19. package/fesm2022/ngwr-back-top.mjs +6 -4
  20. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  21. package/fesm2022/ngwr-border-glow.mjs +12 -9
  22. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  23. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  24. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  25. package/fesm2022/ngwr-calendar.mjs +5 -3
  26. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  27. package/fesm2022/ngwr-card.mjs +2 -2
  28. package/fesm2022/ngwr-card.mjs.map +1 -1
  29. package/fesm2022/ngwr-carousel.mjs +17 -4
  30. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  31. package/fesm2022/ngwr-cascader.mjs +35 -7
  32. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  33. package/fesm2022/ngwr-checkbox.mjs +12 -3
  34. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  35. package/fesm2022/ngwr-circular-text.mjs +2 -2
  36. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  37. package/fesm2022/ngwr-color-picker.mjs +6 -5
  38. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  39. package/fesm2022/ngwr-command-palette.mjs +7 -3
  40. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  41. package/fesm2022/ngwr-context-menu.mjs +7 -7
  42. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  43. package/fesm2022/ngwr-counter.mjs +9 -1
  44. package/fesm2022/ngwr-counter.mjs.map +1 -1
  45. package/fesm2022/ngwr-date-picker.mjs +37 -15
  46. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  47. package/fesm2022/ngwr-density.mjs +10 -2
  48. package/fesm2022/ngwr-density.mjs.map +1 -1
  49. package/fesm2022/ngwr-descriptions.mjs +5 -4
  50. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  51. package/fesm2022/ngwr-dialog.mjs +10 -1
  52. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  53. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  54. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  55. package/fesm2022/ngwr-drawer.mjs +37 -16
  56. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  57. package/fesm2022/ngwr-dropdown.mjs +8 -3
  58. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  59. package/fesm2022/ngwr-event-calendar.mjs +723 -0
  60. package/fesm2022/ngwr-event-calendar.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-file-upload.mjs +2 -2
  64. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  65. package/fesm2022/ngwr-form.mjs +258 -42
  66. package/fesm2022/ngwr-form.mjs.map +1 -1
  67. package/fesm2022/ngwr-fuzzy-text.mjs +15 -1
  68. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  69. package/fesm2022/ngwr-gauge.mjs +8 -3
  70. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  71. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  72. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  73. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  74. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  75. package/fesm2022/ngwr-i18n-en.mjs +89 -5
  76. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  77. package/fesm2022/ngwr-i18n-ru.mjs +90 -5
  78. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  79. package/fesm2022/ngwr-i18n.mjs +94 -3
  80. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  81. package/fesm2022/ngwr-icon.mjs +79 -35
  82. package/fesm2022/ngwr-icon.mjs.map +1 -1
  83. package/fesm2022/ngwr-input-number.mjs +19 -3
  84. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  85. package/fesm2022/ngwr-input.mjs +48 -6
  86. package/fesm2022/ngwr-input.mjs.map +1 -1
  87. package/fesm2022/ngwr-knob.mjs +8 -3
  88. package/fesm2022/ngwr-knob.mjs.map +1 -1
  89. package/fesm2022/ngwr-lightbox.mjs +32 -3
  90. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  91. package/fesm2022/ngwr-line-chart.mjs +3 -3
  92. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  93. package/fesm2022/ngwr-list.mjs +2 -2
  94. package/fesm2022/ngwr-list.mjs.map +1 -1
  95. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  96. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  97. package/fesm2022/ngwr-marquee.mjs +2 -2
  98. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  99. package/fesm2022/ngwr-media.mjs +3 -0
  100. package/fesm2022/ngwr-media.mjs.map +1 -1
  101. package/fesm2022/ngwr-mention.mjs +166 -10
  102. package/fesm2022/ngwr-mention.mjs.map +1 -1
  103. package/fesm2022/ngwr-meter-group.mjs +14 -3
  104. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  105. package/fesm2022/ngwr-overlay.mjs +173 -3
  106. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  107. package/fesm2022/ngwr-page-header.mjs +2 -2
  108. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  109. package/fesm2022/ngwr-pagination.mjs +17 -4
  110. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  111. package/fesm2022/ngwr-popconfirm.mjs +4 -3
  112. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  113. package/fesm2022/ngwr-popover.mjs +10 -3
  114. package/fesm2022/ngwr-popover.mjs.map +1 -1
  115. package/fesm2022/ngwr-progress.mjs +8 -2
  116. package/fesm2022/ngwr-progress.mjs.map +1 -1
  117. package/fesm2022/ngwr-qr.mjs.map +1 -1
  118. package/fesm2022/ngwr-rating.mjs +6 -4
  119. package/fesm2022/ngwr-rating.mjs.map +1 -1
  120. package/fesm2022/ngwr-result.mjs +19 -12
  121. package/fesm2022/ngwr-result.mjs.map +1 -1
  122. package/fesm2022/ngwr-segmented.mjs +2 -2
  123. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  124. package/fesm2022/ngwr-select.mjs +40 -13
  125. package/fesm2022/ngwr-select.mjs.map +1 -1
  126. package/fesm2022/ngwr-shiny-text.mjs +4 -6
  127. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  128. package/fesm2022/ngwr-speed-dial.mjs +11 -3
  129. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  130. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  131. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  132. package/fesm2022/ngwr-squircle.mjs +1 -1
  133. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  134. package/fesm2022/ngwr-star-border.mjs +2 -2
  135. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  136. package/fesm2022/ngwr-switch.mjs +10 -3
  137. package/fesm2022/ngwr-switch.mjs.map +1 -1
  138. package/fesm2022/ngwr-table.mjs +233 -19
  139. package/fesm2022/ngwr-table.mjs.map +1 -1
  140. package/fesm2022/ngwr-tabs.mjs +21 -4
  141. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  142. package/fesm2022/ngwr-textarea.mjs +20 -4
  143. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  144. package/fesm2022/ngwr-theme.mjs +13 -3
  145. package/fesm2022/ngwr-theme.mjs.map +1 -1
  146. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  147. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  148. package/fesm2022/ngwr-toolbar.mjs +2 -2
  149. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  150. package/fesm2022/ngwr-tour.mjs +264 -0
  151. package/fesm2022/ngwr-tour.mjs.map +1 -0
  152. package/fesm2022/ngwr-transfer.mjs +184 -0
  153. package/fesm2022/ngwr-transfer.mjs.map +1 -0
  154. package/fesm2022/ngwr-tree.mjs +27 -9
  155. package/fesm2022/ngwr-tree.mjs.map +1 -1
  156. package/fesm2022/ngwr-typewriter.mjs +2 -2
  157. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  158. package/fesm2022/ngwr-validators.mjs +118 -2
  159. package/fesm2022/ngwr-validators.mjs.map +1 -1
  160. package/fesm2022/ngwr-version.mjs +2 -2
  161. package/fesm2022/ngwr-version.mjs.map +1 -1
  162. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  163. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  164. package/fesm2022/ngwr-waves.mjs +25 -3
  165. package/fesm2022/ngwr-waves.mjs.map +1 -1
  166. package/form/styles/_index.scss +8 -4
  167. package/glitch-text/styles/_index.scss +5 -0
  168. package/gradient-text/styles/_index.scss +5 -0
  169. package/i18n/en.json +233 -0
  170. package/i18n/ru.json +233 -0
  171. package/icon/styles/_index.scss +15 -1
  172. package/input/styles/_index.scss +16 -0
  173. package/input-number/styles/_index.scss +8 -1
  174. package/keyboard/styles/_index.scss +15 -3
  175. package/llms-full.txt +124 -63
  176. package/llms.txt +29 -8
  177. package/loading-bar/styles/_index.scss +5 -0
  178. package/marquee/styles/_index.scss +7 -2
  179. package/mention/styles/_index.scss +23 -0
  180. package/overlay/styles/_index.scss +5 -0
  181. package/package.json +15 -1
  182. package/pagination/styles/_index.scss +12 -0
  183. package/popover/styles/_index.scss +165 -45
  184. package/pull-to-refresh/styles/_index.scss +5 -0
  185. package/result/styles/_index.scss +3 -3
  186. package/schematics/icon-set/index.js +80 -34
  187. package/schematics/icon-set/schema.json +8 -3
  188. package/schematics/ng-add/index.js +23 -6
  189. package/schematics/package.json +3 -0
  190. package/schematics/page/templates.js +17 -21
  191. package/schematics/provider/index.js +31 -13
  192. package/schematics/provider/schema.json +40 -24
  193. package/schematics/use/index.js +5 -1
  194. package/schematics/use/schema.json +8 -3
  195. package/schematics/use/symbol-map.json +7 -176
  196. package/segmented/styles/_index.scss +1 -1
  197. package/select/styles/_index.scss +20 -3
  198. package/shiny-text/styles/_index.scss +5 -0
  199. package/speed-dial/styles/_index.scss +12 -1
  200. package/splitter/styles/_index.scss +7 -1
  201. package/spotlight-card/styles/_index.scss +5 -0
  202. package/squircle/styles/_index.scss +5 -0
  203. package/star-border/styles/_index.scss +5 -0
  204. package/statistic/styles/_index.scss +2 -2
  205. package/styles/_animations.scss +6 -0
  206. package/styles.scss +3 -0
  207. package/table/styles/_index.scss +128 -12
  208. package/theme/styles/_box-model.scss +29 -0
  209. package/theme/styles/_colors.scss +116 -15
  210. package/theme/styles/_dark.scss +65 -7
  211. package/theme/styles/_focus.scss +2 -8
  212. package/theme/styles/_index.scss +1 -0
  213. package/tilt-card/styles/_index.scss +5 -0
  214. package/toast/styles/_index.scss +6 -3
  215. package/tour/styles/_index.scss +63 -0
  216. package/transfer/styles/_index.scss +105 -0
  217. package/types/ngwr-alert.d.ts +4 -1
  218. package/types/ngwr-avatar.d.ts +1 -1
  219. package/types/ngwr-back-top.d.ts +3 -2
  220. package/types/ngwr-badge.d.ts +1 -1
  221. package/types/ngwr-border-glow.d.ts +0 -1
  222. package/types/ngwr-carousel.d.ts +10 -1
  223. package/types/ngwr-cascader.d.ts +13 -1
  224. package/types/ngwr-checkbox.d.ts +9 -1
  225. package/types/ngwr-color-picker.d.ts +1 -0
  226. package/types/ngwr-command-palette.d.ts +4 -1
  227. package/types/ngwr-context-menu.d.ts +1 -0
  228. package/types/ngwr-date-picker.d.ts +14 -4
  229. package/types/ngwr-density.d.ts +9 -2
  230. package/types/ngwr-dialog.d.ts +9 -0
  231. package/types/ngwr-divider.d.ts +1 -1
  232. package/types/ngwr-drawer.d.ts +20 -4
  233. package/types/ngwr-dropdown.d.ts +1 -0
  234. package/types/ngwr-event-calendar.d.ts +358 -0
  235. package/types/ngwr-form.d.ts +177 -20
  236. package/types/ngwr-fuzzy-text.d.ts +8 -0
  237. package/types/ngwr-gauge.d.ts +4 -1
  238. package/types/ngwr-i18n.d.ts +80 -2
  239. package/types/ngwr-icon.d.ts +11 -19
  240. package/types/ngwr-input-number.d.ts +8 -1
  241. package/types/ngwr-input.d.ts +50 -20
  242. package/types/ngwr-knob.d.ts +4 -1
  243. package/types/ngwr-lightbox.d.ts +7 -1
  244. package/types/ngwr-line-chart.d.ts +1 -1
  245. package/types/ngwr-media.d.ts +1 -1
  246. package/types/ngwr-mention.d.ts +45 -1
  247. package/types/ngwr-meter-group.d.ts +9 -1
  248. package/types/ngwr-overlay.d.ts +80 -2
  249. package/types/ngwr-page-header.d.ts +2 -2
  250. package/types/ngwr-pagination.d.ts +15 -2
  251. package/types/ngwr-popconfirm.d.ts +1 -0
  252. package/types/ngwr-popover.d.ts +1 -0
  253. package/types/ngwr-progress.d.ts +4 -1
  254. package/types/ngwr-rating.d.ts +3 -2
  255. package/types/ngwr-result.d.ts +12 -6
  256. package/types/ngwr-segmented.d.ts +6 -0
  257. package/types/ngwr-select.d.ts +19 -7
  258. package/types/ngwr-shiny-text.d.ts +2 -4
  259. package/types/ngwr-speed-dial.d.ts +7 -1
  260. package/types/ngwr-squircle.d.ts +1 -1
  261. package/types/ngwr-switch.d.ts +7 -1
  262. package/types/ngwr-table.d.ts +126 -6
  263. package/types/ngwr-tabs.d.ts +1 -4
  264. package/types/ngwr-textarea.d.ts +8 -1
  265. package/types/ngwr-theme.d.ts +8 -1
  266. package/types/ngwr-toolbar.d.ts +2 -2
  267. package/types/ngwr-tour.d.ts +132 -0
  268. package/types/ngwr-transfer.d.ts +118 -0
  269. package/types/ngwr-tree.d.ts +11 -2
  270. package/types/ngwr-validators.d.ts +62 -2
  271. package/types/ngwr-version.d.ts +2 -2
  272. package/types/ngwr-waves.d.ts +10 -0
  273. package/typewriter/styles/_index.scss +5 -0
  274. package/typography/styles/_index.scss +3 -3
  275. package/virtual-scroll/styles/_index.scss +6 -1
  276. package/waves/styles/_index.scss +26 -0
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # <img src="https://ngwr.dev/assets/images/logo.svg" alt="ngwr logo" height="32px">
1
+ # <img src="https://ngwr.dev/images/logo.svg" alt="ngwr logo" height="32px">
2
2
 
3
3
  [![ngwr website](https://img.shields.io/badge/ngwr.dev-3969e2)](https://ngwr.dev)
4
4
  [![ngwr version](https://img.shields.io/github/package-json/v/thekhegay/ngwr?filename=projects%2Flib%2Fpackage.json&color=%23f51c6a)](https://www.npmjs.com/package/ngwr)
@@ -10,7 +10,7 @@
10
10
  zoneless-ready, responsive, modular SCSS, fully tree-shakable. Built on top of
11
11
  `@angular/cdk` for overlay, portal, and a11y primitives.
12
12
 
13
- > **Status:** active development. v9 is the current major line (Angular 22 peer).
13
+ > **Status:** active development. v10 is the current major line (Angular 22 peer).
14
14
  > Public API is stable across patch releases and still evolving between majors.
15
15
  > [Open an issue](https://github.com/thekhegay/ngwr/issues/new)
16
16
  > if something breaks or feels wrong.
@@ -53,6 +53,15 @@ npm install ngwr @angular/cdk
53
53
  yarn add ngwr @angular/cdk
54
54
  ```
55
55
 
56
+ `@angular/cdk` is the only required peer. Add an icon set and a date library
57
+ only if you use them — `lucide` (or `feather`) for the icon adapters, and
58
+ `date-fns` or `luxon` for the calendar / date-picker adapters. The Quick start
59
+ below registers a lucide icon, so it needs `lucide`:
60
+
61
+ ```shell
62
+ pnpm add lucide
63
+ ```
64
+
56
65
  ## Styles
57
66
 
58
67
  The fastest way — pull in everything (theme tokens + all component styles):
@@ -62,6 +71,11 @@ The fastest way — pull in everything (theme tokens + all component styles):
62
71
  @use 'ngwr';
63
72
  ```
64
73
 
74
+ Good for a spike, but it is every entry point at once — about **247 kB** of CSS
75
+ (~30 kB over the wire), which on its own exceeds the 500 kB initial budget a
76
+ fresh `ng new` ships with. For anything you intend to keep, opt in per component
77
+ below and the sheet stays proportional to what you actually render.
78
+
65
79
  Prefer to opt in per-component? Each component has its own SCSS entry that pulls
66
80
  in the theme automatically:
67
81
 
@@ -161,11 +175,11 @@ export class ProfileForm {
161
175
 
162
176
  ### Components
163
177
 
164
- **Form** — [calendar](https://ngwr.dev/reference/components/calendar), [cascader](https://ngwr.dev/reference/components/cascader), [checkbox](https://ngwr.dev/reference/components/checkbox), [color-picker](https://ngwr.dev/reference/components/color-picker), [date-picker](https://ngwr.dev/reference/components/date-picker), [file-upload](https://ngwr.dev/reference/components/file-upload), [form](https://ngwr.dev/reference/components/form), [form-field](https://ngwr.dev/reference/components/form-field), [input](https://ngwr.dev/reference/components/input), [input-number](https://ngwr.dev/reference/components/input-number), [input-otp](https://ngwr.dev/reference/components/input-otp), [knob](https://ngwr.dev/reference/components/knob), [mention](https://ngwr.dev/reference/components/mention), [radio](https://ngwr.dev/reference/components/radio), [rating](https://ngwr.dev/reference/components/rating), [segmented](https://ngwr.dev/reference/components/segmented), [select](https://ngwr.dev/reference/components/select), [slider](https://ngwr.dev/reference/components/slider), [switch](https://ngwr.dev/reference/components/switch), [textarea](https://ngwr.dev/reference/components/textarea).
178
+ **Form** — [calendar](https://ngwr.dev/reference/components/calendar), [cascader](https://ngwr.dev/reference/components/cascader), [checkbox](https://ngwr.dev/reference/components/checkbox), [color-picker](https://ngwr.dev/reference/components/color-picker), [date-picker](https://ngwr.dev/reference/components/date-picker), [file-upload](https://ngwr.dev/reference/components/file-upload), [form](https://ngwr.dev/reference/components/form), [form-field](https://ngwr.dev/reference/components/form-field), [input](https://ngwr.dev/reference/components/input), [input-number](https://ngwr.dev/reference/components/input-number), [input-otp](https://ngwr.dev/reference/components/input-otp), [knob](https://ngwr.dev/reference/components/knob), [mention](https://ngwr.dev/reference/components/mention), [radio](https://ngwr.dev/reference/components/radio), [rating](https://ngwr.dev/reference/components/rating), [segmented](https://ngwr.dev/reference/components/segmented), [select](https://ngwr.dev/reference/components/select), [slider](https://ngwr.dev/reference/components/slider), [switch](https://ngwr.dev/reference/components/switch), [textarea](https://ngwr.dev/reference/components/textarea), [transfer](https://ngwr.dev/reference/components/transfer).
165
179
 
166
180
  **Buttons** — [button](https://ngwr.dev/reference/components/button), [button-group](https://ngwr.dev/reference/components/button-group), [speed-dial](https://ngwr.dev/reference/components/speed-dial).
167
181
 
168
- **Data** — [drag-drop](https://ngwr.dev/reference/components/drag-drop), [pagination](https://ngwr.dev/reference/components/pagination), [pull-to-refresh](https://ngwr.dev/reference/components/pull-to-refresh), [table](https://ngwr.dev/reference/components/table), [tree](https://ngwr.dev/reference/components/tree), [virtual-scroll](https://ngwr.dev/reference/components/virtual-scroll).
182
+ **Data** — [drag-drop](https://ngwr.dev/reference/components/drag-drop), [event-calendar](https://ngwr.dev/reference/components/event-calendar), [pagination](https://ngwr.dev/reference/components/pagination), [pull-to-refresh](https://ngwr.dev/reference/components/pull-to-refresh), [table](https://ngwr.dev/reference/components/table), [tree](https://ngwr.dev/reference/components/tree), [virtual-scroll](https://ngwr.dev/reference/components/virtual-scroll).
169
183
 
170
184
  **Feedback** — [alert](https://ngwr.dev/reference/components/alert), [empty](https://ngwr.dev/reference/components/empty), [progress](https://ngwr.dev/reference/components/progress), [result](https://ngwr.dev/reference/components/result), [skeleton](https://ngwr.dev/reference/components/skeleton), [spinner](https://ngwr.dev/reference/components/spinner).
171
185
 
@@ -199,11 +213,11 @@ Card packages bundle their related directives: `ngwr/spotlight-card` exports `Wr
199
213
 
200
214
  ### Services
201
215
 
202
- [clipboard](https://ngwr.dev/reference/services/clipboard), [cookie](https://ngwr.dev/reference/services/cookie), [density](https://ngwr.dev/reference/services/density), [hotkey](https://ngwr.dev/reference/services/hotkey), [loading-bar](https://ngwr.dev/reference/services/loading-bar), [media](https://ngwr.dev/reference/services/media), [meta](https://ngwr.dev/reference/services/meta), [platform](https://ngwr.dev/reference/services/platform), [scroll](https://ngwr.dev/reference/services/scroll), [storage](https://ngwr.dev/reference/services/storage), [theme](https://ngwr.dev/reference/services/theme), [i18n](https://ngwr.dev/reference/services/i18n).
216
+ [clipboard](https://ngwr.dev/reference/services/clipboard), [cookie](https://ngwr.dev/reference/services/cookie), [density](https://ngwr.dev/reference/services/density), [hotkey](https://ngwr.dev/reference/services/hotkey), [loading-bar](https://ngwr.dev/reference/services/loading-bar), [media](https://ngwr.dev/reference/services/media), [meta](https://ngwr.dev/reference/services/meta), [platform](https://ngwr.dev/reference/services/platform), [scroll](https://ngwr.dev/reference/services/scroll), [storage](https://ngwr.dev/reference/services/storage), [theme](https://ngwr.dev/reference/services/theme), [tour](https://ngwr.dev/reference/services/tour), [i18n](https://ngwr.dev/reference/services/i18n).
203
217
 
204
218
  ### Validators — `ngwr/validators`
205
219
 
206
- Bundled `ValidatorFn`s composing cleanly with Angular's built-in `Validators`: `cardNumber` (Luhn), `cvc`, `hexColor`, `iban` (mod-97), `match` (sibling control), `maxDate`, `minDate`, `noWhitespace`, `oneOf`, `url`. See [docs](https://ngwr.dev/reference/validators).
220
+ Bundled `ValidatorFn`s composing cleanly with Angular's built-in `Validators`: `cardNumber` (Luhn), `cvc`, `hexColor`, `iban` (mod-97), `match` (sibling control), `matchFields` (group-level), `maxDate`, `minDate`, `noWhitespace`, `oneOf`, `url`. See [docs](https://ngwr.dev/reference/validators).
207
221
 
208
222
  ### Utils — `ngwr/utils`
209
223
 
@@ -225,12 +239,13 @@ Math (`clamp`, `round`), coercion (`numAttr`), css helpers (`resolveCssSize`, `g
225
239
  - **Signal Forms native.** Every value control implements `FormValueControl` / `FormCheckboxControl`, so `[formField]` binds straight through — there is no `ControlValueAccessor` in the library at all. `[(ngModel)]` and reactive forms keep working through Angular's bridge, and every control also works standalone via `[(value)]` / `[(checked)]`.
226
240
  - **CDK-powered.** Overlays, portals, and a11y come from `@angular/cdk`. We add `provideWrOverlay()` so NGWR overlays never collide with other CDK consumers (Material, NG-ZORRO, etc.).
227
241
  - **Mobile & responsive.** Overlays collapse to bottom-sheets on small screens (`provideWrResponsiveOverlays()`), touch targets grow to ≥44px on coarse pointers, a `touch` density preset enlarges every control, and drawer / lightbox / toast / carousel respond to swipe gestures. Fixed surfaces respect `env(safe-area-inset-*)`, and layout components (`descriptions`, `stepper`, `page-header`, `toolbar`, `pagination`, `table`) reflow to their container via container queries. [Guide](https://ngwr.dev/guides/mobile).
228
- - **Table, batteries included.** `wr-table` covers column pinning / resizing / drag-reorder, row selection, expandable rows, grouping, summary rows, CSV export (`exportCsv()`, dependency-free RFC 4180) and a virtualized body — all opt-in inputs on the one component. Excel (`.xlsx`) export is deliberately not shipped: it would mean a third-party dependency.
229
- - **Tree-shakable.** 127 separate ng-packagr entry points — import only what you use. Per-component FESM bundles are small: a median of ~3 KB gzipped, the heaviest (`ngwr/table`) ~18 KB. The whole catalog gzips to ~490 KB — but real apps pull a handful of entries. The only runtime dependency is `tslib`.
242
+ - **Table, batteries included.** `wr-table` covers column pinning / resizing / drag-reorder, row selection, expandable rows, grouping, tree rows (`childrenKey` — the forest flattens into the same `<tbody>`, so pinning and cell templates keep working at every depth, and the table announces a `treegrid`), summary rows, CSV export (`exportCsv()`, dependency-free RFC 4180) and a virtualized body — all opt-in inputs on the one component. Excel (`.xlsx`) export is deliberately not shipped: it would mean a third-party dependency.
243
+ - **Tree-shakable.** 130 separate ng-packagr entry points — import only what you use. Per-component FESM bundles are small: a median of ~3 KB gzipped, the heaviest (`ngwr/select`) ~20 KB. The whole catalog gzips to ~516 KB — but real apps pull a handful of entries. The only runtime dependency is `tslib`.
230
244
  - **Modular SCSS.** Component styles are scoped through CSS custom properties. Theme tokens live in `ngwr/theme`; utilities (`grid`, `reset`) and the breakpoints SCSS API are opt-in.
231
245
  - **Tree-shaken icons.** `provideWrIcons(lucideIcons({ plus: Plus }))` registers only the icons you actually import. Dev-mode validation warns about unregistered icons.
232
246
  - **Reactbits ports, dependency-free.** All animation ports are reimplemented with vanilla DOM + Web Animations API / `IntersectionObserver` / `requestAnimationFrame` / raw WebGL — no GSAP, no `motion/react`, no `matter-js`, no `ogl`.
233
247
  - **Motion respects the OS.** Every animation component short-circuits to its final state under `prefers-reduced-motion`.
248
+ - **Legible to agents.** Every docs page also serves as markdown at the same URL plus `.md` — [reference/components/select.md](https://ngwr.dev/reference/components/select.md) is that page's prose, code samples and API tables without the site chrome. The whole catalog is at [llms-full.txt](https://ngwr.dev/llms-full.txt), a quick-ref at [llms.txt](https://ngwr.dev/llms.txt).
234
249
 
235
250
  ## Contributing
236
251
 
@@ -1,3 +1,8 @@
1
+ // Pull the whole theme so a standalone `@use 'ngwr/<name>'` brings in every
2
+ // design token this stylesheet references. Sass deduplicates `@use` per
3
+ // compilation, so the umbrella sheet still emits the theme only once.
4
+ @use '../../theme/styles' as theme;
5
+
1
6
  .wr-action-sheet {
2
7
  display: flex;
3
8
  flex-direction: column;
@@ -65,7 +70,7 @@
65
70
  }
66
71
 
67
72
  &--destructive {
68
- color: var(--wr-color-danger);
73
+ color: var(--wr-color-danger-ink);
69
74
  }
70
75
 
71
76
  &--cancel {
@@ -14,10 +14,14 @@
14
14
  border-radius: var(--wr-badge-radius);
15
15
  font-size: var(--wr-badge-font-size);
16
16
  font-weight: var(--wr-badge-font-weight);
17
- // line-height 1 + min-height: flex centres the tight glyph box vertically,
18
- // instead of line-height baking in asymmetric leading (which left small
19
- // sizes looking top-heavy).
20
- line-height: 1;
17
+ // The flex line is centred exactly (`align-items` above), but the glyphs inside
18
+ // it were not: Blink floors the half-leading, so any odd
19
+ // `line-height − (ascent + descent)` paints the text box half a pixel high —
20
+ // measured 4px above / 5px below at md, 6/7 at lg. `normal` leaves no leading
21
+ // to round, and the min-heights below still fix the box, so the badge keeps its
22
+ // 18 / 24 / 30px sizes.
23
+ //
24
+ line-height: normal;
21
25
  white-space: nowrap;
22
26
 
23
27
  // Defaults — sized modifiers override these
@@ -37,11 +41,17 @@
37
41
  --wr-badge-min-height: 1.125rem;
38
42
  }
39
43
 
44
+ // `lg` used to jump two steps on the axes that decide its footprint while the
45
+ // type only moved one — padding-x 6 → 8 → 12 and min-height 18 → 24 → 32,
46
+ // against a font of 10 → 12 → 14. Result: a third more badge for a sixth more
47
+ // text, which is why it read as oversized next to `md`. One step each:
48
+ // 6 → 8 → 10 and 18 → 24 → 30, holding min-height a constant 4px above the
49
+ // intrinsic `font-size + 2 × padding-y` at every size.
40
50
  &--lg {
41
51
  --wr-badge-padding-y: 0.375rem;
42
- --wr-badge-padding-x: 0.75rem;
52
+ --wr-badge-padding-x: 0.625rem;
43
53
  --wr-badge-font-size: var(--wr-text-sm);
44
- --wr-badge-min-height: 2rem;
54
+ --wr-badge-min-height: 1.875rem;
45
55
  }
46
56
 
47
57
  // Shape — default `rounded` keeps the small radius from the defaults
@@ -77,7 +87,7 @@
77
87
 
78
88
  @each $name in theme.$colors {
79
89
  &.wr-badge--#{$name} {
80
- color: var(--wr-color-#{$name});
90
+ color: var(--wr-color-#{$name}-ink);
81
91
  }
82
92
  }
83
93
  }
@@ -19,12 +19,21 @@
19
19
  --wr-tag-padding-x: 0.5rem;
20
20
  --wr-tag-font-size: var(--wr-text-xs);
21
21
  --wr-tag-font-weight: 500;
22
- --wr-tag-line-height: 1rem;
22
+ // `normal`, not a fixed `1rem`: a 16px line box against the font's own 15px
23
+ // content area leaves half a pixel of leading per side, Blink floors it, and
24
+ // the label paints 1px high — 3px above / 4px below, while an adornment icon
25
+ // sits dead centre at 4/4. That 0.5px split between icon and text centres is
26
+ // what reads as "the tag's alignment has drifted".
27
+ --wr-tag-line-height: normal;
28
+ // Zero leading would otherwise shrink the tag 22px -> 21px, so the box is
29
+ // floored explicitly instead of being an accident of the line height.
30
+ --wr-tag-min-height: 1.375rem;
23
31
 
24
32
  color: var(--wr-tag-color);
25
33
  background: var(--wr-tag-bg);
26
34
  border: 1px solid var(--wr-tag-border);
27
35
  border-radius: var(--wr-tag-radius);
36
+ min-height: var(--wr-tag-min-height);
28
37
  padding: calc(var(--wr-tag-padding-y) * var(--wr-density-y, 1)) calc(var(--wr-tag-padding-x) * var(--wr-density-x, 1));
29
38
  font-family: var(--wr-font-family-base);
30
39
  font-size: var(--wr-tag-font-size);
@@ -66,13 +75,13 @@
66
75
  --wr-tag-border: var(--wr-color-#{$name});
67
76
 
68
77
  &.wr-tag--outlined {
69
- --wr-tag-color: var(--wr-color-#{$name});
78
+ --wr-tag-color: var(--wr-color-#{$name}-ink);
70
79
  --wr-tag-bg: rgba(var(--wr-color-#{$name}-rgb), 0.06);
71
80
  --wr-tag-border: rgba(var(--wr-color-#{$name}-rgb), 0.25);
72
81
  }
73
82
 
74
83
  &.wr-tag--transparent {
75
- --wr-tag-color: var(--wr-color-#{$name});
84
+ --wr-tag-color: var(--wr-color-#{$name}-ink);
76
85
  --wr-tag-bg: rgba(var(--wr-color-#{$name}-rgb), 0.1);
77
86
  --wr-tag-border: transparent;
78
87
  }
@@ -1,3 +1,8 @@
1
+ // Pull the whole theme so a standalone `@use 'ngwr/<name>'` brings in every
2
+ // design token this stylesheet references. Sass deduplicates `@use` per
3
+ // compilation, so the umbrella sheet still emits the theme only once.
4
+ @use '../../theme/styles' as theme;
5
+
1
6
  // Cursor-tracked border glow — ports the reactbits.dev BorderGlow effect.
2
7
  // All visual state is driven by two custom properties the component writes:
3
8
  // --wr-border-glow-edge-proximity 0..100, scales with pointer-to-edge distance
@@ -59,6 +59,15 @@
59
59
  --wr-icon-size: var(--wr-btn-icon-size);
60
60
  color: inherit;
61
61
  flex: 0 0 auto;
62
+
63
+ // Lucide and feather draw on a 24-unit grid with a 2-unit safe area, so a
64
+ // twelfth of the icon box is transparent on each side. `padding-x` sits
65
+ // outside that slack and `gap` inside it, so the declared numbers and the
66
+ // optical ones diverge — measured at md: 14.6px from the button edge to the
67
+ // first ink against 11.9px on the label side, and 8.7px to the label against
68
+ // a declared 6px gap. Reclaiming the slack makes the spacing look like what
69
+ // the tokens say.
70
+ margin-inline: calc(var(--wr-btn-icon-size) / -12);
62
71
  }
63
72
 
64
73
  &__spin {
@@ -72,6 +81,39 @@
72
81
  &__label {
73
82
  flex: 0 1 auto;
74
83
  min-width: 0;
84
+
85
+ // Icon-only buttons project no content, but the label span is still in the
86
+ // template — as a zero-width flex item it kept claiming its share of `gap`
87
+ // and pushed the glyph off-centre by exactly gap/2. Taking it out of the
88
+ // flow removes the gap with it.
89
+ &:empty {
90
+ display: none;
91
+ }
92
+ }
93
+
94
+ // Icon-only — square, at any density and any size.
95
+ //
96
+ // The height is intrinsic (`line-height + 2·padding-y + 2·border`), so nothing
97
+ // can be hardcoded and `aspect-ratio` has no definite axis to work from. Both
98
+ // axes reduce to the same expression instead: mirror the block padding on the
99
+ // inline axis, and give the icon box the line-height as its square. The glyph
100
+ // keeps its own `--wr-btn-icon-size` and centres inside that box.
101
+ //
102
+ // `block` is excluded — it is width:100% by contract, and squaring it would
103
+ // turn a full-width button into a giant tile.
104
+ &:has(> &__label:empty):not(&--block) {
105
+ padding-inline: calc(var(--wr-btn-padding-y) * var(--wr-density-y, 1));
106
+
107
+ .wr-btn__icon {
108
+ width: var(--wr-btn-line-height);
109
+ height: var(--wr-btn-line-height);
110
+ display: inline-flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ // No label to sit next to, so there is no optical gap to correct — and a
114
+ // negative margin here would pull the glyph off the square's centre.
115
+ margin-inline: 0;
116
+ }
75
117
  }
76
118
 
77
119
  // Sizes — share the `--wr-control-*` contract (22 / 30 / 36 px) so button,
@@ -155,7 +197,12 @@
155
197
  }
156
198
 
157
199
  &.wr-btn--outlined {
158
- --wr-btn-color: var(--wr-color-#{$name});
200
+ // `-ink` is the intent darkened (light) / lightened (dark) until it
201
+ // clears 4.5:1 as its own label — the base hue does not: in light,
202
+ // warning as a label is 1.71:1. `--wr-color-light-ink` resolves to the
203
+ // page's own ink, which is why the `light` special case is gone; the
204
+ // border still carries the intent.
205
+ --wr-btn-color: var(--wr-color-#{$name}-ink);
159
206
  --wr-btn-bg: transparent;
160
207
  --wr-btn-border: rgba(var(--wr-color-#{$name}-rgb), 0.4);
161
208
 
@@ -115,7 +115,15 @@
115
115
  letter-spacing: 0.04em;
116
116
  }
117
117
 
118
- // Day grid
118
+ // Day grid. `__body` exists so the weekday row and the week rows share a
119
+ // `role="grid"` parent; it repeats the host's column gap so the two-sibling
120
+ // layout it replaced renders identically.
121
+ &__body {
122
+ display: flex;
123
+ flex-direction: column;
124
+ gap: 0.5rem;
125
+ }
126
+
119
127
  &__grid {
120
128
  display: flex;
121
129
  flex-direction: column;
@@ -1,3 +1,8 @@
1
+ // Pull the whole theme so a standalone `@use 'ngwr/<name>'` brings in every
2
+ // design token this stylesheet references. Sass deduplicates `@use` per
3
+ // compilation, so the umbrella sheet still emits the theme only once.
4
+ @use '../../theme/styles' as theme;
5
+
1
6
  // Circular text (reactbits port). Each char is absolutely positioned at
2
7
  // the spinner's centre, then transformed `rotate() translateY(-radius)`
3
8
  // so it lands on the perimeter of a circle of constant radius. The host
@@ -17,7 +22,7 @@
17
22
  font-weight: 700;
18
23
  text-align: center;
19
24
  user-select: none;
20
- transition: transform 0.6s cubic-bezier(0.2, 0.9, 0.3, 1.4);
25
+ transition: transform 0.6s var(--wr-ease-spring);
21
26
 
22
27
  &__spin {
23
28
  position: absolute;
@@ -1,7 +1,7 @@
1
1
  // Density multipliers. Components multiply their paddings (and the
2
2
  // occasional height / line-height) by these scalars via `calc()`.
3
3
  //
4
- // `default` resolves to `1` everywhere — touching `data-wr-density` is
4
+ // `md` resolves to `1` everywhere — touching `data-wr-density` is
5
5
  // pure opt-in. Components without density-aware paddings just keep
6
6
  // their static values.
7
7
  //
@@ -11,6 +11,8 @@
11
11
  :root {
12
12
  --wr-density-y: 1;
13
13
  --wr-density-x: 1;
14
+ // `-text` and `-gap` are declared for consumers to read; no shipped
15
+ // component multiplies by either yet. `-y` / `-x` are the live ones.
14
16
  --wr-density-text: 1;
15
17
  --wr-density-gap: 1;
16
18
  }
@@ -39,7 +39,7 @@
39
39
  z-index: 1000;
40
40
  pointer-events: auto;
41
41
  opacity: 0;
42
- transition: opacity 200ms cubic-bezier(0.25, 0.8, 0.25, 1);
42
+ transition: opacity 200ms var(--wr-ease-out);
43
43
  }
44
44
 
45
45
  .cdk-overlay-backdrop.cdk-overlay-backdrop-showing {
@@ -61,6 +61,19 @@
61
61
 
62
62
  display: flex;
63
63
  flex-direction: column;
64
+ // Containing block for the corner dismiss button — see `.wr-dialog__close`.
65
+ //
66
+ // `!important` is load-bearing, not laziness. Service-opened overlays use CDK's
67
+ // `GlobalPositionStrategy`, which positions `.cdk-global-overlay-wrapper` and
68
+ // writes `position: static` INLINE onto the pane — and here the pane IS the
69
+ // panel. Inline beats any ordinary rule, and setting it imperatively does not
70
+ // survive either: CDK re-applies the strategy after the overlay is attached.
71
+ //
72
+ // Layout-neutral: the pane stays a flex item of the wrapper and is centred
73
+ // exactly as before; `relative` with no offsets only establishes the containing
74
+ // block (and activates the `z-index` that `.cdk-overlay-pane` already declares,
75
+ // identically for every pane, so relative stacking is unchanged).
76
+ position: relative !important;
64
77
  min-width: var(--wr-dialog-min-width);
65
78
  max-width: calc(100vw - 2rem);
66
79
  max-height: calc(100vh - 2rem);
@@ -87,6 +100,58 @@
87
100
  border-bottom: 1px solid var(--wr-color-outline);
88
101
  }
89
102
 
103
+ // Built-in dismiss (×), parked in the panel's top-right corner. The service
104
+ // adds it — and `--closable` alongside it — unless `closable: false`.
105
+ &__close {
106
+ position: absolute;
107
+ // Centre on the title's first line: its text box starts one padding-y down
108
+ // and is 1.5rem tall.
109
+ inset-block-start: calc(var(--wr-dialog-padding-y) + 0.75rem);
110
+ inset-inline-end: var(--wr-dialog-padding-x);
111
+ transform: translateY(-50%);
112
+ z-index: 1;
113
+
114
+ appearance: none;
115
+ background: transparent;
116
+ border: 0;
117
+ padding: 0.25rem;
118
+ color: var(--wr-color-on-surface-muted);
119
+ cursor: pointer;
120
+ border-radius: var(--wr-border-radius-sm);
121
+ transition:
122
+ color var(--wr-transition-base),
123
+ background var(--wr-transition-base);
124
+
125
+ // The glyph is a bare `.wr-icon__svg`, sized in `em` — so pin the font-size
126
+ // rather than `--wr-icon-size` (which only drives `<wr-icon>` hosts). Gives a
127
+ // deterministic 16px ✕ in a 24px box instead of inheriting whatever the
128
+ // surrounding text happens to be.
129
+ font-size: 1rem;
130
+ line-height: 0;
131
+
132
+ // `$positioned: true` — the default would set `position: relative` under
133
+ // `(pointer: coarse)` and drop the button out of the corner on touch.
134
+ @include theme.touch-target($positioned: true); // 16px glyph -> 44px tap area
135
+
136
+ &:hover {
137
+ color: var(--wr-color-on-surface);
138
+ background: var(--wr-color-hover);
139
+ }
140
+
141
+ &:focus-visible {
142
+ @include theme.focus-ring;
143
+ }
144
+ }
145
+
146
+ // Reserve the gutter so a long heading wraps instead of running under the ×.
147
+ // The modifier belongs to the panel block (`wr-dialog-panel`), which is the
148
+ // element the service tags; `wr-dialog__*` are the parts inside it.
149
+ .wr-dialog-panel--closable & {
150
+ &__title {
151
+ padding-inline-end: calc(var(--wr-dialog-padding-x) + 1.75rem);
152
+ }
153
+ }
154
+
90
155
  &__content {
91
156
  padding: var(--wr-dialog-padding-y) var(--wr-dialog-padding-x);
92
157
  overflow: auto;
@@ -124,4 +189,3 @@
124
189
  transform: scale(1);
125
190
  }
126
191
  }
127
-
@@ -7,8 +7,10 @@
7
7
  // .cdk-drag-preview — floating preview that follows the cursor
8
8
  // .cdk-drag-placeholder — empty slot left at the source position
9
9
  // .cdk-drag-animating — in the post-drop settle animation
10
- // We theme them so the default look matches the rest of the lib; apps
11
- // can override `.cdk-drag-preview` etc. per drop list.
10
+ // Every one of them is qualified with a `.wr-sortable-list*` class. Bare
11
+ // `.cdk-drag-*` rules are global, and a UI library has no business restyling
12
+ // a consumer's own CDK drop lists — nor `wr-table`'s column drag, which was
13
+ // picking up this component's dashed placeholder and lift shadow.
12
14
 
13
15
  .wr-sortable-list {
14
16
  display: block;
@@ -71,7 +73,11 @@
71
73
 
72
74
  // CDK overlays applied by drag-drop
73
75
 
74
- .cdk-drag-preview {
76
+ // The preview is a CLONE of the dragged row that CDK moves to `document.body`,
77
+ // so an ancestor selector cannot reach it — but the clone keeps the row's own
78
+ // class, which can. Verified on a real drag: the preview lands in `<body>`
79
+ // carrying `cdk-drag wr-sortable-list__item cdk-drag-preview`.
80
+ .cdk-drag-preview.wr-sortable-list__item {
75
81
  box-sizing: border-box;
76
82
  color: var(--wr-color-on-surface);
77
83
  font-family: var(--wr-font-family-base);
@@ -86,7 +92,8 @@
86
92
  // CDK sets pointer-events to none on the preview; we keep visuals only.
87
93
  }
88
94
 
89
- .cdk-drag-placeholder {
95
+ // The placeholder stays in the list, so scoping by ancestor is enough here.
96
+ .wr-sortable-list .cdk-drag-placeholder {
90
97
  opacity: 0.35;
91
98
  // Subtle dashed outline so users see where the item came from.
92
99
  background: rgba(var(--wr-color-outline-rgb), 0.6);
@@ -95,10 +102,16 @@
95
102
  outline-offset: -1px;
96
103
  }
97
104
 
98
- .cdk-drag-animating {
99
- transition: transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.1);
105
+ // Also the preview, not a row in the list: CDK keeps `cdk-drag-preview` on the
106
+ // clone and adds `cdk-drag-animating` while it flies back to the drop slot.
107
+ // Verified on a real drop — the element carries
108
+ // `cdk-drag wr-sortable-list__item cdk-drag-preview cdk-drag-animating` and sits
109
+ // in `<body>`. It has to come after the preview rule, which sets
110
+ // `transition: none` at the same specificity.
111
+ .cdk-drag-animating.wr-sortable-list__item {
112
+ transition: transform 0.18s var(--wr-ease-spring);
100
113
  }
101
114
 
102
115
  .wr-sortable-list__list.cdk-drop-list-dragging .wr-sortable-list__item:not(.cdk-drag-placeholder) {
103
- transition: transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.1);
116
+ transition: transform 0.18s var(--wr-ease-spring);
104
117
  }
@@ -31,7 +31,10 @@
31
31
  // between the panel and the title / content / footer slots, so the panel's
32
32
  // column layout stops one level short: the footer wouldn't pin to the bottom
33
33
  // and the body wouldn't scroll. Pass the layout through the interposed host.
34
- .wr-drawer-overlay.wr-drawer__panel > * {
34
+ // `:not(.wr-drawer__close)` — the dismiss button is a direct child too, and it
35
+ // is corner-positioned chrome, not the content column. Left in, `width: 100%`
36
+ // stretched it across the whole panel.
37
+ .wr-drawer-overlay.wr-drawer__panel > *:not(.wr-drawer__close) {
35
38
  display: flex;
36
39
  flex: 1 1 auto;
37
40
  flex-direction: column;
@@ -47,6 +50,18 @@
47
50
 
48
51
  display: flex;
49
52
  flex-direction: column;
53
+ // Anchor for the corner dismiss button. The panel is the overlay pane itself
54
+ // for service drawers but a nested div for `<wr-drawer>`.
55
+ //
56
+ // `!important` for the service case: CDK's `GlobalPositionStrategy` writes
57
+ // `position: static` inline onto the pane and re-applies it after attach, so
58
+ // neither a plain rule nor an imperative assignment survives. Harmless for the
59
+ // component case, where the panel is an ordinary div we own.
60
+ //
61
+ // A right-edge drawer hid this bug for a while — its top-right corner coincides
62
+ // with the viewport's, so the misplaced button looked correct. Any other side
63
+ // exposes it immediately.
64
+ position: relative !important;
50
65
  width: 100%;
51
66
  height: 100%;
52
67
  background: var(--wr-drawer-bg);
@@ -134,6 +149,51 @@
134
149
  border-bottom: 1px solid var(--wr-color-outline);
135
150
  }
136
151
 
152
+ // Built-in dismiss (×) in the panel's top-right corner — rendered by the
153
+ // component template, appended by `WrDrawerManager` for service drawers.
154
+ &__close {
155
+ position: absolute;
156
+ // Centre on the title's first line: 1rem of padding, then a 1.5rem text box.
157
+ inset-block-start: 1.75rem;
158
+ inset-inline-end: 1.25rem;
159
+ transform: translateY(-50%);
160
+ z-index: 1;
161
+
162
+ appearance: none;
163
+ background: transparent;
164
+ border: 0;
165
+ padding: 0.25rem;
166
+ color: var(--wr-color-on-surface-muted);
167
+ cursor: pointer;
168
+ border-radius: var(--wr-border-radius-sm);
169
+ transition:
170
+ color var(--wr-transition-base),
171
+ background var(--wr-transition-base);
172
+
173
+ // Sized via font-size, not `--wr-icon-size`: the glyph is a bare
174
+ // `.wr-icon__svg`, which measures itself in `em`.
175
+ font-size: 1rem;
176
+ line-height: 0;
177
+
178
+ // `$positioned: true` — the default sets `position: relative` under
179
+ // `(pointer: coarse)`, which would drop the button out of the corner.
180
+ @include theme.touch-target($positioned: true);
181
+
182
+ &:hover {
183
+ color: var(--wr-color-on-surface);
184
+ background: var(--wr-color-hover);
185
+ }
186
+
187
+ &:focus-visible {
188
+ @include theme.focus-ring;
189
+ }
190
+ }
191
+
192
+ // Reserve the gutter so a long heading wraps instead of running under the ×.
193
+ &__panel--closable &__title {
194
+ padding-inline-end: 3rem;
195
+ }
196
+
137
197
  &__content {
138
198
  flex: 1 1 auto;
139
199
  padding: 1rem 1.25rem;