ngwr 14.7.0 → 14.8.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 (152) hide show
  1. package/bar-chart/styles/_index.scss +1 -0
  2. package/calendar-heatmap/styles/_index.scss +1 -0
  3. package/cascader/styles/_rules.scss +86 -14
  4. package/date-picker/styles/_index.scss +30 -0
  5. package/density/styles/_index.scss +4 -2
  6. package/donut-chart/styles/_index.scss +10 -0
  7. package/dropdown/styles/_index.scss +67 -5
  8. package/event-calendar/styles/_index.scss +209 -35
  9. package/fesm2022/ngwr-bar-chart.mjs +29 -4
  10. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  11. package/fesm2022/ngwr-calendar-heatmap.mjs +59 -4
  12. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  13. package/fesm2022/ngwr-cascader.mjs +2 -2
  14. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  15. package/fesm2022/ngwr-checkbox.mjs +12 -2
  16. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  17. package/fesm2022/ngwr-date-picker.mjs +705 -46
  18. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  19. package/fesm2022/ngwr-donut-chart.mjs +46 -4
  20. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  21. package/fesm2022/ngwr-dropdown.mjs +166 -17
  22. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  23. package/fesm2022/ngwr-event-calendar.mjs +9 -2
  24. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  25. package/fesm2022/ngwr-form.mjs +52 -1
  26. package/fesm2022/ngwr-form.mjs.map +1 -1
  27. package/fesm2022/ngwr-gauge.mjs +33 -4
  28. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  29. package/fesm2022/ngwr-i18n-ar.mjs +2 -0
  30. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  31. package/fesm2022/ngwr-i18n-cs.mjs +2 -0
  32. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  33. package/fesm2022/ngwr-i18n-de.mjs +2 -0
  34. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  35. package/fesm2022/ngwr-i18n-en.mjs +5 -0
  36. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  37. package/fesm2022/ngwr-i18n-es.mjs +2 -0
  38. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  39. package/fesm2022/ngwr-i18n-fr.mjs +2 -0
  40. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  41. package/fesm2022/ngwr-i18n-he.mjs +2 -0
  42. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  43. package/fesm2022/ngwr-i18n-hi.mjs +2 -0
  44. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  45. package/fesm2022/ngwr-i18n-id.mjs +2 -0
  46. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  47. package/fesm2022/ngwr-i18n-it.mjs +2 -0
  48. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  49. package/fesm2022/ngwr-i18n-ja.mjs +2 -0
  50. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  51. package/fesm2022/ngwr-i18n-ko.mjs +2 -0
  52. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  53. package/fesm2022/ngwr-i18n-nl.mjs +2 -0
  54. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  55. package/fesm2022/ngwr-i18n-pl.mjs +2 -0
  56. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  57. package/fesm2022/ngwr-i18n-pt.mjs +2 -0
  58. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  59. package/fesm2022/ngwr-i18n-ru.mjs +2 -0
  60. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  61. package/fesm2022/ngwr-i18n-sv.mjs +2 -0
  62. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  63. package/fesm2022/ngwr-i18n-tr.mjs +2 -0
  64. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  65. package/fesm2022/ngwr-i18n-uk.mjs +2 -0
  66. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  67. package/fesm2022/ngwr-i18n-vi.mjs +2 -0
  68. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  69. package/fesm2022/ngwr-i18n-zh-TW.mjs +2 -0
  70. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  71. package/fesm2022/ngwr-i18n-zh.mjs +2 -0
  72. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  73. package/fesm2022/ngwr-input-number.mjs +12 -0
  74. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  75. package/fesm2022/ngwr-line-chart.mjs +16 -5
  76. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  77. package/fesm2022/ngwr-meter-group-testing.mjs +7 -3
  78. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  79. package/fesm2022/ngwr-meter-group.mjs +24 -4
  80. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  81. package/fesm2022/ngwr-page-header.mjs +10 -2
  82. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  83. package/fesm2022/ngwr-popover.mjs +569 -7
  84. package/fesm2022/ngwr-popover.mjs.map +1 -1
  85. package/fesm2022/ngwr-sidebar.mjs +7 -0
  86. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  87. package/fesm2022/ngwr-sparkline.mjs +82 -8
  88. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  89. package/fesm2022/ngwr-table.mjs +1 -1
  90. package/fesm2022/ngwr-table.mjs.map +1 -1
  91. package/fesm2022/ngwr-toolbar.mjs +7 -0
  92. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  93. package/fesm2022/ngwr-version.mjs +1 -1
  94. package/fesm2022/ngwr-version.mjs.map +1 -1
  95. package/form/styles/_index.scss +11 -1
  96. package/gauge/styles/_index.scss +1 -0
  97. package/i18n/ar.json +3 -1
  98. package/i18n/cs.json +3 -1
  99. package/i18n/de.json +3 -1
  100. package/i18n/en.json +3 -1
  101. package/i18n/es.json +3 -1
  102. package/i18n/fr.json +3 -1
  103. package/i18n/he.json +3 -1
  104. package/i18n/hi.json +3 -1
  105. package/i18n/id.json +3 -1
  106. package/i18n/it.json +3 -1
  107. package/i18n/ja.json +3 -1
  108. package/i18n/ko.json +3 -1
  109. package/i18n/nl.json +3 -1
  110. package/i18n/pl.json +3 -1
  111. package/i18n/pt.json +3 -1
  112. package/i18n/ru.json +3 -1
  113. package/i18n/sv.json +3 -1
  114. package/i18n/tr.json +3 -1
  115. package/i18n/uk.json +3 -1
  116. package/i18n/vi.json +3 -1
  117. package/i18n/zh-TW.json +3 -1
  118. package/i18n/zh.json +3 -1
  119. package/input/styles/_index.scss +19 -0
  120. package/input-number/styles/_index.scss +69 -0
  121. package/line-chart/styles/_index.scss +30 -2
  122. package/llms-full.txt +3 -3
  123. package/meter-group/styles/_index.scss +1 -0
  124. package/overlay/styles/_arrow.scss +27 -2
  125. package/package.json +1 -1
  126. package/page-header/styles/_index.scss +37 -1
  127. package/pagination/styles/_index.scss +9 -5
  128. package/popover/styles/_index.scss +73 -5
  129. package/select/styles/_index.scss +48 -9
  130. package/sidebar/styles/_index.scss +34 -2
  131. package/sparkline/styles/_index.scss +19 -0
  132. package/toolbar/styles/_index.scss +35 -1
  133. package/tree/styles/_index.scss +45 -6
  134. package/types/ngwr-bar-chart.d.ts +19 -1
  135. package/types/ngwr-calendar-heatmap.d.ts +29 -1
  136. package/types/ngwr-checkbox.d.ts +2 -0
  137. package/types/ngwr-date-picker.d.ts +308 -43
  138. package/types/ngwr-donut-chart.d.ts +24 -1
  139. package/types/ngwr-dropdown.d.ts +22 -2
  140. package/types/ngwr-event-calendar.d.ts +8 -0
  141. package/types/ngwr-form.d.ts +35 -5
  142. package/types/ngwr-gauge.d.ts +20 -1
  143. package/types/ngwr-input-number.d.ts +7 -0
  144. package/types/ngwr-line-chart.d.ts +9 -1
  145. package/types/ngwr-meter-group-testing.d.ts +3 -2
  146. package/types/ngwr-meter-group.d.ts +14 -1
  147. package/types/ngwr-page-header.d.ts +10 -2
  148. package/types/ngwr-popover.d.ts +154 -3
  149. package/types/ngwr-sidebar.d.ts +7 -0
  150. package/types/ngwr-sparkline.d.ts +43 -1
  151. package/types/ngwr-toolbar.d.ts +7 -0
  152. package/types/ngwr-version.d.ts +1 -1
@@ -1,4 +1,5 @@
1
1
  @use '../../theme/styles' as theme;
2
+ @use '../../popover/styles'; // the `.wr-tooltip` chip the hover tooltip renders into
2
3
 
3
4
  .wr-bar-chart {
4
5
  display: block;
@@ -1,4 +1,5 @@
1
1
  @use '../../theme/styles' as theme;
2
+ @use '../../popover/styles'; // the `.wr-tooltip` chip the hover tooltip renders into
2
3
 
3
4
  .wr-calendar-heatmap {
4
5
  display: inline-block;
@@ -2,6 +2,8 @@
2
2
  // is a horizontal row of columns where each column lists the children
3
3
  // of the previously-active node. Picking a leaf commits the path.
4
4
 
5
+ @use '../../theme/styles/mixins' as theme;
6
+
5
7
  // `focus` is the one theme partial these rules still load that emits CSS of its
6
8
  // own — the shared ring mixin lives in the same file as the baseline
7
9
  // `.wr-*:focus-visible` rules, and there is no mixin-only module to take it from.
@@ -21,15 +23,49 @@
21
23
  --wr-cascader-line-height: var(--wr-control-line-height-md);
22
24
  --wr-cascader-col-width: 12rem;
23
25
  --wr-cascader-max-height: 16rem;
24
- // Trigger width floor — hooked for the same reason as `--wr-select-min-width`:
25
- // in a narrow grid column the literal wins over `minmax(0, 1fr)` and the
26
- // trigger overhangs its cell, and the only escape was overriding
27
- // `.wr-cascader__trigger` from outside. Set it to 0 to defer to the layout.
26
+ // Trigger width floor, the same contract as `--wr-select-min-width`. Despite
27
+ // the name it is a DEFAULT width rather than a minimum: an explicit `width`,
28
+ // `width: 100%` in a narrow parent, a `minmax(0, 1fr)` cell and a shrinking
29
+ // flex item all win over it (see `::after` below). Set it to 0 to size a bare
30
+ // cascader to its path alone. This hook is the only way to lower it: a
31
+ // `min-width` on `.wr-cascader__trigger`, the override that did it before the
32
+ // hook existed, no longer reaches the floor.
28
33
  --wr-cascader-min-width: 12rem;
29
34
 
30
- display: inline-flex;
35
+ // One column that shrinks to whatever the layout gives it and, left to size
36
+ // itself, grows to the widest thing in it — the trigger's path or the floor.
37
+ // The floor used to be a `min-width` on the trigger, which no width on the
38
+ // host could beat: `style="width: 6rem"` drew a 192px trigger in a 96px host.
39
+ // `minmax(0, …)` also drops the path's text from the host's min-content —
40
+ // together the two held a cascader showing a path at 210px in a 200px flex
41
+ // row beside a 120px sibling, 138px past the row's edge — so it now shrinks
42
+ // as a flex item the way `[wrInput]` does and the path truncates instead.
43
+ display: inline-grid;
44
+ grid-template-columns: minmax(0, 1fr);
45
+ // The spacer below lands in a row of its own, and it must be a FIXED 0 rather
46
+ // than an implicit `auto` one: a grid shares height beyond its content among
47
+ // its auto rows, so a host stretched by a taller flex or grid row, or given a
48
+ // `height`, drew a 45px trigger in a 60px host with an empty band beneath it.
49
+ grid-template-rows: auto 0;
31
50
  vertical-align: middle;
32
51
 
52
+ // The floor as a zero-height spacer in the same column. A grid track's
53
+ // max-content is its widest item, so a host sized to its content is at least
54
+ // `--wr-cascader-min-width` wide; `max-width: 100%` is ignored while that
55
+ // size is being worked out and applies once the column exists, so a narrower
56
+ // host caps the spacer instead of the spacer stretching the host. `flex: 0 0
57
+ // 0` keeps it from taking room beside the trigger if a consumer turns the
58
+ // host into a flex container (the floor is then inert, never in the way). The
59
+ // template renders exactly one element into the host — the trigger — so this
60
+ // is the column's only other item, and the zero row is the spacer's.
61
+ &::after {
62
+ content: '';
63
+ flex: 0 0 0;
64
+ width: var(--wr-cascader-min-width);
65
+ max-width: 100%;
66
+ height: 0;
67
+ }
68
+
33
69
  &--disabled {
34
70
  --wr-cascader-color: var(--wr-color-on-surface-muted);
35
71
  --wr-cascader-bg: var(--wr-color-fill);
@@ -57,7 +93,10 @@
57
93
  align-items: center;
58
94
  gap: 0.5rem;
59
95
  width: 100%;
60
- min-width: var(--wr-cascader-min-width);
96
+ // Not the floor — that lives on the host, where a width can beat it. Zero
97
+ // lets the trigger follow the host down and the path's ellipsis take the
98
+ // difference.
99
+ min-width: 0;
61
100
  appearance: none;
62
101
  background: var(--wr-cascader-bg);
63
102
  color: var(--wr-cascader-color);
@@ -86,6 +125,20 @@
86
125
  &:disabled {
87
126
  cursor: not-allowed;
88
127
  }
128
+
129
+ // The ×'s touch halo (on `__clear`) CLEARS the path, and nothing undoes that,
130
+ // so it must never reach past the control it belongs to. A 32px halo on a 22px
131
+ // `sm` trigger overhung its border by 5px above and below, and a tap 3px above
132
+ // the trigger, on whatever sits over it, cleared this one. Clipping the block
133
+ // axis bounds the halo to the trigger's own padding box: 20 / 28 / 32px tall
134
+ // for sm / md / lg, and still inside under any padding, line-height or density.
135
+ // A cap re-derived from the hooks overhung again on md and lg as soon as the
136
+ // trigger's `padding-block` was set directly. `clip` rather than `hidden`, so
137
+ // there is no scroll container and no baseline change, and the inline axis stays
138
+ // visible.
139
+ @media (pointer: coarse) {
140
+ overflow-y: clip;
141
+ }
89
142
  }
90
143
 
91
144
  // A read-only trigger still takes focus and still shows its path, so it keeps
@@ -105,6 +158,13 @@
105
158
  &__value,
106
159
  &__placeholder {
107
160
  flex: 1 1 auto;
161
+ // The text line is what gives the trigger its size's height, so it has to
162
+ // exist when there is no text. Nothing chosen and no placeholder left an
163
+ // empty span with no line box, and the trigger fell to the chevron's 1em:
164
+ // measured 18 / 24 / 28px for sm / md / lg, where the contract is 22 / 30 / 36.
165
+ // `1lh` is the span's own line, not the hook, so a `line-height` set on the
166
+ // trigger itself shortens an empty trigger the same way it shortens a filled one.
167
+ min-height: 1lh;
108
168
  overflow: hidden;
109
169
  text-overflow: ellipsis;
110
170
  white-space: nowrap;
@@ -130,6 +190,14 @@
130
190
  justify-content: center;
131
191
  width: 1.125rem;
132
192
  height: 1.125rem;
193
+ // Never adds to the text line, so choosing a value cannot resize the trigger.
194
+ // The 18px circle is taller than `sm`'s 16px line and made an `sm` cascader
195
+ // with a value 24px tall. A symmetric negative margin of at least half the box
196
+ // takes the × out of the line's cross size, for any box up to 2rem, and
197
+ // `align-items: center` keeps the circle centred as drawn. A margin worked out
198
+ // from the hook and the 18px literal let a restyled `.wr-cascader__clear` grow
199
+ // the trigger again: a 24px box made sm / md / lg 28 / 36 / 42px with a value.
200
+ margin-block: -1rem;
133
201
  border-radius: 999px;
134
202
  color: var(--wr-color-on-surface-muted);
135
203
  cursor: pointer;
@@ -141,6 +209,15 @@
141
209
  background: rgba(var(--wr-color-on-surface-rgb), 0.06);
142
210
  color: var(--wr-color-on-surface);
143
211
  }
212
+
213
+ // The same 32px tap area the × has always had on touch, as a halo rather
214
+ // than a box. Growing the box itself put 32px inside the text line: with a
215
+ // value, sm / md / lg measured 38 / 42 / 44px under a coarse pointer against
216
+ // 22 / 30 / 36 without one, so `lg` read as `md` and a pick moved the row.
217
+ // 2rem rather than the mixin's 44px default, which would reach over the
218
+ // chevron 8px away and turn a tap meant to open the panel into a clear. The
219
+ // trigger clips the halo's height to its own (see `__trigger`).
220
+ @include theme.touch-target($size: 2rem);
144
221
  }
145
222
  }
146
223
 
@@ -244,15 +321,10 @@
244
321
  }
245
322
  }
246
323
 
247
- // Touch pointers: grow the clear button and make the column option rows ~44px
248
- // tall so each is a comfortable tap target. Fine pointers keep the compact
249
- // desktop sizing above.
324
+ // Touch pointers: make the column option rows ~44px tall so each is a
325
+ // comfortable tap target (the clear button's own tap area is on `__clear`).
326
+ // Fine pointers keep the compact desktop sizing above.
250
327
  @media (pointer: coarse) {
251
- .wr-cascader__clear {
252
- width: 2rem;
253
- height: 2rem;
254
- }
255
-
256
328
  .wr-cascader-panel .wr-cascader__opt {
257
329
  padding-top: 0.75rem;
258
330
  padding-bottom: 0.75rem;
@@ -1,5 +1,20 @@
1
1
  @use '../../theme/styles' as theme;
2
2
 
3
+ // The refusal's live region — a screen reader's copy of what the border says. One
4
+ // element per block, since a BEM class is public API: the range picker's is its own.
5
+ .wr-date-picker__sr-only,
6
+ .wr-date-range-picker__sr-only {
7
+ position: absolute;
8
+ width: 1px;
9
+ height: 1px;
10
+ padding: 0;
11
+ margin: -1px;
12
+ overflow: hidden;
13
+ clip: rect(0, 0, 0, 0);
14
+ white-space: nowrap;
15
+ border: 0;
16
+ }
17
+
3
18
  .wr-date-picker {
4
19
  display: inline-block;
5
20
 
@@ -51,6 +66,21 @@
51
66
  }
52
67
  }
53
68
 
69
+ // A typed entry the picker refused, once it is on show (Enter, or leaving the
70
+ // field). The group owns the border — it strips the inner input's — so the hook
71
+ // is the group's, set exactly as `.wr-form-field--invalid` sets it, and at the
72
+ // same (0,3,0) so a focused group's primary border does not win it back while
73
+ // the user is correcting the text.
74
+ // color-ok: the colour is the SIGHTED half of a state that is not carried by
75
+ // colour alone — the input takes `aria-invalid` and the reason is announced
76
+ // through the picker's live region, or through the surrounding field's message.
77
+ // `danger` against the default `--wr-color-outline` also separates in lightness
78
+ // (3.11:1 light), so the cue survives greyscale.
79
+ .wr-date-picker.wr-date-picker--invalid .wr-input-group,
80
+ .wr-date-range-picker.wr-date-range-picker--invalid .wr-input-group {
81
+ --wr-input-group-border: var(--wr-color-danger);
82
+ }
83
+
54
84
  // Overlay pane — z-index isolation only. <wr-calendar> + the time panel
55
85
  // bring their own chrome.
56
86
  .wr-date-picker-overlay {
@@ -11,8 +11,10 @@
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
+ // `-text` is declared for consumers to read; no shipped component multiplies
15
+ // by it yet. `-gap` scales the space a layout component puts between the
16
+ // controls projected into it, and is there for consumers to read as well.
17
+ // `-y` / `-x` are the padding multipliers.
16
18
  --wr-density-text: 1;
17
19
  --wr-density-gap: 1;
18
20
  }
@@ -1,4 +1,5 @@
1
1
  @use '../../theme/styles' as theme;
2
+ @use '../../popover/styles'; // the `.wr-tooltip` chip the hover tooltip renders into
2
3
 
3
4
  .wr-donut-chart {
4
5
  display: inline-flex;
@@ -27,6 +28,15 @@
27
28
  align-items: center;
28
29
  justify-content: center;
29
30
  text-align: center;
31
+ // The box covers the whole drawing, so it took every pointer event meant for
32
+ // the arcs under it and no slice could be hovered. Only the text itself is
33
+ // hittable, which keeps it selectable.
34
+ pointer-events: none;
35
+ }
36
+
37
+ &__center-value,
38
+ &__center-label {
39
+ pointer-events: auto;
30
40
  }
31
41
 
32
42
  &__center-value {
@@ -1,5 +1,17 @@
1
1
  @use '../../theme/styles' as theme;
2
2
  @use '../../overlay/styles'; // shared .wr-overlay-sheet / .wr-overlay-backdrop for responsive mode
3
+ @use '../../overlay/styles/arrow';
4
+
5
+ /// Gap between the trigger and the menu, as pane padding on the edge facing the
6
+ /// trigger. Padding rather than a CDK offset so a pointer crossing it is still
7
+ /// over the overlay — a `trigger="hover"` menu closes the moment the pointer is
8
+ /// anywhere else.
9
+ $gap: 0.25rem;
10
+
11
+ /// The gap with the arrow on. The arrow reaches `arrow.$half + 1px` (4px) out of
12
+ /// the menu's border, so the plain gap would put its tip ON the trigger; this is
13
+ /// the 8px `wr-popover` keeps, leaving the same 4px between tip and control.
14
+ $arrow-gap: 0.5rem;
3
15
 
4
16
  // The directive marks its host `.wr-dropdown-trigger` — `.wr-dropdown` below is
5
17
  // reachable only if a consumer applies it by hand, which is why it stays: the
@@ -41,17 +53,19 @@
41
53
  }
42
54
 
43
55
  .wr-dropdown-overlay {
44
- // Positional offsets between trigger and menu by side.
56
+ // Positional offsets between trigger and menu by side. The directive swaps the
57
+ // placement class when the menu flips, so the gap moves to the edge that faces
58
+ // the trigger from where it actually opened.
45
59
  &--top,
46
60
  &--top-start,
47
61
  &--top-end {
48
- padding-bottom: 0.25rem;
62
+ padding-bottom: $gap;
49
63
  }
50
64
 
51
65
  &--bottom,
52
66
  &--bottom-start,
53
67
  &--bottom-end {
54
- padding-top: 0.25rem;
68
+ padding-top: $gap;
55
69
  }
56
70
 
57
71
  // The gap sits on the pane edge that faces the trigger. `left` / `right` map
@@ -59,12 +73,60 @@
59
73
  // `FlexibleConnectedPositionStrategy` already resolves against the ambient
60
74
  // `Directionality` — so the padding has to follow the same axis, logically.
61
75
  &--left {
62
- padding-inline-end: 0.25rem;
76
+ padding-inline-end: $gap;
63
77
  }
64
78
 
65
79
  &--right {
66
- padding-inline-start: 0.25rem;
80
+ padding-inline-start: $gap;
67
81
  }
82
+
83
+ // Same edges, wider, when the arrow is drawn. The placement half sits inside
84
+ // `:where()`, so each rule weighs ONE class, exactly like its plain twin above,
85
+ // and wins on source order alone. Two classes of weight would also beat a
86
+ // consumer's own `.wr-dropdown-overlay--bottom-start { padding-top: … }` —
87
+ // which has been the only way to retune this gap, since it has no hook — and
88
+ // with the arrow on by default every such override would be silently ignored.
89
+ &--arrow {
90
+ &:where(.wr-dropdown-overlay--top, .wr-dropdown-overlay--top-start, .wr-dropdown-overlay--top-end) {
91
+ padding-bottom: $arrow-gap;
92
+ }
93
+
94
+ &:where(.wr-dropdown-overlay--bottom, .wr-dropdown-overlay--bottom-start, .wr-dropdown-overlay--bottom-end) {
95
+ padding-top: $arrow-gap;
96
+ }
97
+
98
+ &:where(.wr-dropdown-overlay--left) {
99
+ padding-inline-end: $arrow-gap;
100
+ }
101
+
102
+ &:where(.wr-dropdown-overlay--right) {
103
+ padding-inline-start: $arrow-gap;
104
+ }
105
+ }
106
+ }
107
+
108
+ // The arrow — the rotated square `wr-popover` and `wr-popconfirm` draw, from the
109
+ // same mixin, so the three anchored panels cannot drift apart. Filled and
110
+ // outlined from the menu's OWN hooks rather than the tokens behind them: a
111
+ // consumer who retints one menu through `--wr-dropdown-bg` / `-border` would
112
+ // otherwise get an arrow in the old colours. The `::after` inherits the hooks
113
+ // from the menu it belongs to, so the per-instance value reaches it.
114
+ //
115
+ // Eight placements, not twelve: `WrDropdownPosition` has no `left-start` and
116
+ // friends, and those rules could never match.
117
+ @include arrow.anchored-arrow(
118
+ $pane: '.wr-dropdown-overlay',
119
+ $panel: '> .wr-dropdown-menu',
120
+ $background: var(--wr-dropdown-bg),
121
+ $border: var(--wr-dropdown-border),
122
+ $placements-used: (top, top-start, top-end, bottom, bottom-start, bottom-end, left, right)
123
+ );
124
+
125
+ // `[arrow]="false"` — the directive leaves `--arrow` off the pane and the square
126
+ // is never generated. The mixin's own sheet rule covers `responsive`, which gets
127
+ // no `--arrow` either.
128
+ .wr-dropdown-overlay:not(.wr-dropdown-overlay--arrow) > .wr-dropdown-menu::after {
129
+ content: none;
68
130
  }
69
131
 
70
132
  .wr-dropdown-item {