ngwr 12.1.0 → 13.0.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 (187) hide show
  1. package/README.md +11 -1
  2. package/alert/styles/_index.scss +11 -4
  3. package/badge/styles/_index.scss +30 -0
  4. package/badge/styles/_tag.scss +15 -1
  5. package/border-glow/border-glow.scss +1 -1
  6. package/border-glow/styles/_index.scss +15 -233
  7. package/border-glow/styles/_rules.scss +228 -0
  8. package/breadcrumbs/breadcrumbs.scss +1 -1
  9. package/breadcrumbs/styles/_index.scss +15 -78
  10. package/breadcrumbs/styles/_rules.scss +84 -0
  11. package/card/card.scss +1 -1
  12. package/card/styles/_index.scss +15 -96
  13. package/card/styles/_rules.scss +96 -0
  14. package/cascader/cascader.scss +1 -1
  15. package/cascader/styles/_index.scss +15 -244
  16. package/cascader/styles/_rules.scss +261 -0
  17. package/checkbox/styles/_index.scss +7 -0
  18. package/circular-text/circular-text.scss +1 -1
  19. package/circular-text/styles/_index.scss +15 -63
  20. package/circular-text/styles/_rules.scss +58 -0
  21. package/color-picker/styles/_index.scss +8 -0
  22. package/descriptions/styles/_index.scss +13 -3
  23. package/drag-drop/sortable-list.scss +1 -1
  24. package/drag-drop/styles/_index.scss +14 -143
  25. package/drag-drop/styles/_rules.scss +151 -0
  26. package/drawer/styles/_index.scss +95 -1
  27. package/falling-text/falling-text.scss +1 -1
  28. package/falling-text/styles/_index.scss +15 -36
  29. package/falling-text/styles/_rules.scss +31 -0
  30. package/fesm2022/ngwr-border-glow.mjs +2 -2
  31. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  32. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  33. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  34. package/fesm2022/ngwr-card.mjs +2 -2
  35. package/fesm2022/ngwr-card.mjs.map +1 -1
  36. package/fesm2022/ngwr-cascader.mjs +27 -9
  37. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  38. package/fesm2022/ngwr-checkbox.mjs +86 -8
  39. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  40. package/fesm2022/ngwr-circular-text.mjs +2 -2
  41. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  42. package/fesm2022/ngwr-color-picker.mjs +57 -7
  43. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  44. package/fesm2022/ngwr-date-picker.mjs +8 -0
  45. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  46. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  47. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  48. package/fesm2022/ngwr-drawer.mjs +6 -0
  49. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  50. package/fesm2022/ngwr-falling-text.mjs +2 -2
  51. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  52. package/fesm2022/ngwr-file-upload.mjs +29 -8
  53. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  54. package/fesm2022/ngwr-form.mjs +48 -1
  55. package/fesm2022/ngwr-form.mjs.map +1 -1
  56. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  57. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  58. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  59. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  60. package/fesm2022/ngwr-input-otp.mjs +41 -3
  61. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  62. package/fesm2022/ngwr-knob.mjs +17 -2
  63. package/fesm2022/ngwr-knob.mjs.map +1 -1
  64. package/fesm2022/ngwr-lightbox.mjs +2 -2
  65. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  66. package/fesm2022/ngwr-list.mjs +2 -2
  67. package/fesm2022/ngwr-list.mjs.map +1 -1
  68. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  69. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  70. package/fesm2022/ngwr-marquee.mjs +2 -2
  71. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  72. package/fesm2022/ngwr-pagination.mjs +1 -1
  73. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  74. package/fesm2022/ngwr-radio.mjs +63 -8
  75. package/fesm2022/ngwr-radio.mjs.map +1 -1
  76. package/fesm2022/ngwr-rating.mjs +17 -2
  77. package/fesm2022/ngwr-rating.mjs.map +1 -1
  78. package/fesm2022/ngwr-segmented.mjs +22 -3
  79. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  80. package/fesm2022/ngwr-select.mjs +59 -15
  81. package/fesm2022/ngwr-select.mjs.map +1 -1
  82. package/fesm2022/ngwr-shiny-text.mjs +2 -2
  83. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  84. package/fesm2022/ngwr-slider.mjs +21 -6
  85. package/fesm2022/ngwr-slider.mjs.map +1 -1
  86. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  87. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  88. package/fesm2022/ngwr-star-border.mjs +2 -2
  89. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  90. package/fesm2022/ngwr-switch.mjs +44 -4
  91. package/fesm2022/ngwr-switch.mjs.map +1 -1
  92. package/fesm2022/ngwr-table.mjs +1 -1
  93. package/fesm2022/ngwr-table.mjs.map +1 -1
  94. package/fesm2022/ngwr-textarea.mjs +5 -2
  95. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  96. package/fesm2022/ngwr-theme.mjs +41 -1
  97. package/fesm2022/ngwr-theme.mjs.map +1 -1
  98. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  99. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  100. package/fesm2022/ngwr-transfer.mjs +38 -6
  101. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  102. package/fesm2022/ngwr-tree.mjs +33 -7
  103. package/fesm2022/ngwr-tree.mjs.map +1 -1
  104. package/fesm2022/ngwr-typewriter.mjs +2 -2
  105. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  106. package/fesm2022/ngwr-version.mjs +1 -1
  107. package/fesm2022/ngwr-version.mjs.map +1 -1
  108. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  109. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  110. package/fesm2022/ngwr-waves.mjs +2 -2
  111. package/fesm2022/ngwr-waves.mjs.map +1 -1
  112. package/file-upload/styles/_index.scss +6 -0
  113. package/glitch-text/glitch-text.scss +1 -1
  114. package/glitch-text/styles/_index.scss +14 -164
  115. package/glitch-text/styles/_rules.scss +160 -0
  116. package/gradient-text/gradient-text.scss +1 -1
  117. package/gradient-text/styles/_index.scss +15 -118
  118. package/gradient-text/styles/_rules.scss +113 -0
  119. package/input/styles/_index.scss +13 -0
  120. package/input-otp/styles/_index.scss +8 -0
  121. package/lightbox/lightbox.scss +1 -1
  122. package/lightbox/styles/_index.scss +15 -191
  123. package/lightbox/styles/_rules.scss +198 -0
  124. package/list/list.scss +1 -1
  125. package/list/styles/_index.scss +15 -101
  126. package/list/styles/_rules.scss +108 -0
  127. package/llms-full.txt +3 -3
  128. package/loading-bar/loading-bar.scss +1 -1
  129. package/loading-bar/styles/_index.scss +15 -33
  130. package/loading-bar/styles/_rules.scss +28 -0
  131. package/marquee/marquee.scss +1 -1
  132. package/marquee/styles/_index.scss +15 -155
  133. package/marquee/styles/_rules.scss +150 -0
  134. package/overlay/styles/_arrow.scss +243 -0
  135. package/package.json +1 -1
  136. package/popconfirm/styles/_index.scss +17 -0
  137. package/popover/styles/_index.scss +49 -207
  138. package/segmented/styles/_index.scss +8 -0
  139. package/select/styles/_index.scss +47 -5
  140. package/shiny-text/shiny-text.scss +1 -1
  141. package/shiny-text/styles/_index.scss +14 -105
  142. package/shiny-text/styles/_rules.scss +101 -0
  143. package/sidebar/styles/_index.scss +4 -1
  144. package/slider/styles/_index.scss +8 -0
  145. package/spotlight-card/spotlight-card.scss +1 -1
  146. package/spotlight-card/styles/_index.scss +15 -52
  147. package/spotlight-card/styles/_rules.scss +47 -0
  148. package/star-border/star-border.scss +1 -1
  149. package/star-border/styles/_index.scss +15 -125
  150. package/star-border/styles/_rules.scss +120 -0
  151. package/stepper/styles/_index.scss +44 -5
  152. package/switch/styles/_index.scss +7 -0
  153. package/theme/styles/_dark.scss +81 -4
  154. package/theme/styles/_index.scss +1 -0
  155. package/theme/styles/_mixins.scss +10 -0
  156. package/theme/styles/_motion.scss +94 -0
  157. package/tilt-card/styles/_index.scss +15 -45
  158. package/tilt-card/styles/_rules.scss +40 -0
  159. package/tilt-card/tilt-card.scss +1 -1
  160. package/tree/styles/_index.scss +25 -3
  161. package/types/ngwr-cascader.d.ts +17 -1
  162. package/types/ngwr-checkbox.d.ts +51 -3
  163. package/types/ngwr-color-picker.d.ts +19 -1
  164. package/types/ngwr-file-upload.d.ts +18 -1
  165. package/types/ngwr-form.d.ts +51 -2
  166. package/types/ngwr-input-otp.d.ts +23 -1
  167. package/types/ngwr-knob.d.ts +14 -0
  168. package/types/ngwr-radio.d.ts +37 -2
  169. package/types/ngwr-rating.d.ts +14 -0
  170. package/types/ngwr-segmented.d.ts +18 -1
  171. package/types/ngwr-select.d.ts +29 -3
  172. package/types/ngwr-slider.d.ts +14 -1
  173. package/types/ngwr-switch.d.ts +26 -2
  174. package/types/ngwr-textarea.d.ts +3 -0
  175. package/types/ngwr-theme.d.ts +24 -0
  176. package/types/ngwr-transfer.d.ts +17 -1
  177. package/types/ngwr-tree.d.ts +21 -1
  178. package/types/ngwr-version.d.ts +1 -1
  179. package/typewriter/styles/_index.scss +15 -38
  180. package/typewriter/styles/_rules.scss +33 -0
  181. package/typewriter/typewriter.scss +1 -1
  182. package/virtual-scroll/styles/_index.scss +15 -32
  183. package/virtual-scroll/styles/_rules.scss +27 -0
  184. package/virtual-scroll/virtual-scroll.scss +1 -1
  185. package/waves/styles/_index.scss +15 -50
  186. package/waves/styles/_rules.scss +45 -0
  187. package/waves/waves.scss +1 -1
@@ -1,33 +1,15 @@
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
-
6
- .wr-loading-bar {
7
- position: fixed;
8
- top: 0;
9
- inset-inline: 0;
10
- z-index: var(--wr-z-top, 9999);
11
- pointer-events: none;
12
-
13
- &__track {
14
- width: 100%;
15
- overflow: hidden;
16
- opacity: 0;
17
- transition: opacity 0.2s ease;
18
- }
19
-
20
- &--active {
21
- opacity: 1;
22
- }
23
-
24
- &__fill {
25
- width: 0;
26
- height: 2px;
27
- background: var(--wr-color-primary);
28
- box-shadow: 0 0 8px rgb(var(--wr-color-primary-rgb) / 60%);
29
- transition:
30
- width 0.15s ease-out,
31
- opacity 0.2s ease;
32
- }
33
- }
1
+ // Public Sass entry for `@use 'ngwr/loading-bar'`.
2
+ //
3
+ // Pulls the whole theme so a standalone import still brings in every design
4
+ // token these rules reference, then loads the rules themselves from `_rules`.
5
+ //
6
+ // The split is what keeps the token layer out of the JavaScript bundle.
7
+ // `loading-bar.scss` is the component's `styleUrl`, and a component stylesheet is
8
+ // its OWN Sass compilation — `@use` only deduplicates within one. So while the
9
+ // umbrella sheet emits the theme once, forwarding it from here would inline a
10
+ // second, byte-identical copy of `:root`, `[data-theme='dark']` and the
11
+ // box-sizing reset into the compiled component styles, which ng-packagr then
12
+ // embeds in the FESM bundle as a string. `loading-bar.scss` forwards `_rules`
13
+ // instead, so it carries this component's own CSS and nothing else.
14
+ @use '../../theme/styles';
15
+ @forward 'rules';
@@ -0,0 +1,28 @@
1
+ .wr-loading-bar {
2
+ position: fixed;
3
+ top: 0;
4
+ inset-inline: 0;
5
+ z-index: var(--wr-z-top, 9999);
6
+ pointer-events: none;
7
+
8
+ &__track {
9
+ width: 100%;
10
+ overflow: hidden;
11
+ opacity: 0;
12
+ transition: opacity 0.2s ease;
13
+ }
14
+
15
+ &--active {
16
+ opacity: 1;
17
+ }
18
+
19
+ &__fill {
20
+ width: 0;
21
+ height: 2px;
22
+ background: var(--wr-color-primary);
23
+ box-shadow: 0 0 8px rgb(var(--wr-color-primary-rgb) / 60%);
24
+ transition:
25
+ width 0.15s ease-out,
26
+ opacity 0.2s ease;
27
+ }
28
+ }
@@ -1 +1 @@
1
- @forward './styles';
1
+ @forward './styles/rules';
@@ -1,155 +1,15 @@
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
-
6
- // Endless marquee (reactbits LogoLoop port).
7
- // Vars driven from component inputs:
8
- // --wr-marquee-gap gap between items (px)
9
- // --wr-marquee-height item height (px)
10
- // --wr-marquee-fade-color edge fade colour (falls back to page bg)
11
-
12
- .wr-marquee {
13
- --wr-marquee-gap: 32px;
14
- --wr-marquee-height: 28px;
15
- // Default to the lib's surface colour; consumers can override via
16
- // `[fadeOutColor]` or by setting `--wr-marquee-fade-color` directly.
17
- --wr-marquee-fade-color-auto: var(--wr-color-surface, #ffffff);
18
-
19
- position: relative;
20
- display: block;
21
- width: 100%;
22
- overflow: hidden;
23
-
24
- &--scale-hover {
25
- padding-top: calc(var(--wr-marquee-height) * 0.1);
26
- padding-bottom: calc(var(--wr-marquee-height) * 0.1);
27
- }
28
-
29
- &__track {
30
- display: flex;
31
- width: max-content;
32
- will-change: transform;
33
- user-select: none;
34
- position: relative;
35
- z-index: 0;
36
- }
37
-
38
- &__list {
39
- display: flex;
40
- align-items: center;
41
- margin: 0;
42
- padding: 0;
43
- list-style: none;
44
- }
45
-
46
- &__item {
47
- flex: 0 0 auto;
48
- // The whole strip is physical, not textual: `[direction]` is literally
49
- // `'left' | 'right'`, the track is driven by `translate3d(-offset px, 0, 0)`
50
- // against a `getBoundingClientRect().width` measurement of one sequence, and
51
- // the edge fades are `left`/`right` gradients. The item gap is the seam of
52
- // that physical loop — it has to match the offset the track wraps at, so it
53
- // stays on the same axis the animation runs on.
54
- // rtl-ok: seam gap of a physically-animated track (see the note above)
55
- margin-right: var(--wr-marquee-gap);
56
- font-size: var(--wr-marquee-height);
57
- line-height: 1;
58
- }
59
-
60
- &__item:last-child {
61
- // Restates the interior gap on the last item so the join between two copies
62
- // of the sequence is spaced like the gaps inside it.
63
- // rtl-ok: same physical loop axis as the interior gap above
64
- margin-right: var(--wr-marquee-gap);
65
- }
66
-
67
- &__node {
68
- display: inline-flex;
69
- align-items: center;
70
- }
71
-
72
- &__item img {
73
- height: var(--wr-marquee-height);
74
- width: auto;
75
- display: block;
76
- object-fit: contain;
77
- image-rendering: -webkit-optimize-contrast;
78
- -webkit-user-drag: none;
79
- pointer-events: none;
80
- transition: transform var(--wr-duration-slow) var(--wr-ease-out);
81
- }
82
-
83
- &--scale-hover &__item {
84
- overflow: visible;
85
- }
86
-
87
- &--scale-hover &__item:hover img,
88
- &--scale-hover &__item:hover &__node {
89
- transform: scale(1.2);
90
- transform-origin: center center;
91
- }
92
-
93
- &--scale-hover &__node {
94
- transition: transform var(--wr-duration-slow) var(--wr-ease-out);
95
- }
96
-
97
- &__link {
98
- display: inline-flex;
99
- align-items: center;
100
- text-decoration: none;
101
- border-radius: 4px;
102
- transition: opacity 0.2s ease;
103
-
104
- &:hover {
105
- opacity: 0.8;
106
- }
107
-
108
- &:focus-visible {
109
- outline: 2px solid currentColor;
110
- outline-offset: 2px;
111
- }
112
- }
113
-
114
- &--fade::before,
115
- &--fade::after {
116
- content: '';
117
- position: absolute;
118
- top: 0;
119
- bottom: 0;
120
- width: clamp(24px, 8%, 120px);
121
- pointer-events: none;
122
- z-index: 10;
123
- }
124
-
125
- &--fade::before {
126
- // rtl-ok: paired with the physical `linear-gradient(to right, …)` below, which has no logical form
127
- left: 0;
128
- background: linear-gradient(
129
- to right,
130
- var(--wr-marquee-fade-color, var(--wr-marquee-fade-color-auto)) 0%,
131
- rgba(0, 0, 0, 0) 100%
132
- );
133
- }
134
-
135
- &--fade::after {
136
- // rtl-ok: paired with the physical `linear-gradient(to left, …)` below, which has no logical form
137
- right: 0;
138
- background: linear-gradient(
139
- to left,
140
- var(--wr-marquee-fade-color, var(--wr-marquee-fade-color-auto)) 0%,
141
- rgba(0, 0, 0, 0) 100%
142
- );
143
- }
144
-
145
- @media (prefers-reduced-motion: reduce) {
146
- .wr-marquee__track {
147
- transform: translate3d(0, 0, 0) !important;
148
- }
149
-
150
- .wr-marquee__item img,
151
- .wr-marquee__node {
152
- transition: none !important;
153
- }
154
- }
155
- }
1
+ // Public Sass entry for `@use 'ngwr/marquee'`.
2
+ //
3
+ // Pulls the whole theme so a standalone import still brings in every design
4
+ // token these rules reference, then loads the rules themselves from `_rules`.
5
+ //
6
+ // The split is what keeps the token layer out of the JavaScript bundle.
7
+ // `marquee.scss` is the component's `styleUrl`, and a component stylesheet is
8
+ // its OWN Sass compilation — `@use` only deduplicates within one. So while the
9
+ // umbrella sheet emits the theme once, forwarding it from here would inline a
10
+ // second, byte-identical copy of `:root`, `[data-theme='dark']` and the
11
+ // box-sizing reset into the compiled component styles, which ng-packagr then
12
+ // embeds in the FESM bundle as a string. `marquee.scss` forwards `_rules`
13
+ // instead, so it carries this component's own CSS and nothing else.
14
+ @use '../../theme/styles';
15
+ @forward 'rules';
@@ -0,0 +1,150 @@
1
+ // Endless marquee (reactbits LogoLoop port).
2
+ // Vars driven from component inputs:
3
+ // --wr-marquee-gap gap between items (px)
4
+ // --wr-marquee-height item height (px)
5
+ // --wr-marquee-fade-color edge fade colour (falls back to page bg)
6
+
7
+ .wr-marquee {
8
+ --wr-marquee-gap: 32px;
9
+ --wr-marquee-height: 28px;
10
+ // Default to the lib's surface colour; consumers can override via
11
+ // `[fadeOutColor]` or by setting `--wr-marquee-fade-color` directly.
12
+ --wr-marquee-fade-color-auto: var(--wr-color-surface, #ffffff);
13
+
14
+ position: relative;
15
+ display: block;
16
+ width: 100%;
17
+ overflow: hidden;
18
+
19
+ &--scale-hover {
20
+ padding-top: calc(var(--wr-marquee-height) * 0.1);
21
+ padding-bottom: calc(var(--wr-marquee-height) * 0.1);
22
+ }
23
+
24
+ &__track {
25
+ display: flex;
26
+ width: max-content;
27
+ will-change: transform;
28
+ user-select: none;
29
+ position: relative;
30
+ z-index: 0;
31
+ }
32
+
33
+ &__list {
34
+ display: flex;
35
+ align-items: center;
36
+ margin: 0;
37
+ padding: 0;
38
+ list-style: none;
39
+ }
40
+
41
+ &__item {
42
+ flex: 0 0 auto;
43
+ // The whole strip is physical, not textual: `[direction]` is literally
44
+ // `'left' | 'right'`, the track is driven by `translate3d(-offset px, 0, 0)`
45
+ // against a `getBoundingClientRect().width` measurement of one sequence, and
46
+ // the edge fades are `left`/`right` gradients. The item gap is the seam of
47
+ // that physical loop — it has to match the offset the track wraps at, so it
48
+ // stays on the same axis the animation runs on.
49
+ // rtl-ok: seam gap of a physically-animated track (see the note above)
50
+ margin-right: var(--wr-marquee-gap);
51
+ font-size: var(--wr-marquee-height);
52
+ line-height: 1;
53
+ }
54
+
55
+ &__item:last-child {
56
+ // Restates the interior gap on the last item so the join between two copies
57
+ // of the sequence is spaced like the gaps inside it.
58
+ // rtl-ok: same physical loop axis as the interior gap above
59
+ margin-right: var(--wr-marquee-gap);
60
+ }
61
+
62
+ &__node {
63
+ display: inline-flex;
64
+ align-items: center;
65
+ }
66
+
67
+ &__item img {
68
+ height: var(--wr-marquee-height);
69
+ width: auto;
70
+ display: block;
71
+ object-fit: contain;
72
+ image-rendering: -webkit-optimize-contrast;
73
+ -webkit-user-drag: none;
74
+ pointer-events: none;
75
+ transition: transform var(--wr-duration-slow) var(--wr-ease-out);
76
+ }
77
+
78
+ &--scale-hover &__item {
79
+ overflow: visible;
80
+ }
81
+
82
+ &--scale-hover &__item:hover img,
83
+ &--scale-hover &__item:hover &__node {
84
+ transform: scale(1.2);
85
+ transform-origin: center center;
86
+ }
87
+
88
+ &--scale-hover &__node {
89
+ transition: transform var(--wr-duration-slow) var(--wr-ease-out);
90
+ }
91
+
92
+ &__link {
93
+ display: inline-flex;
94
+ align-items: center;
95
+ text-decoration: none;
96
+ border-radius: 4px;
97
+ transition: opacity 0.2s ease;
98
+
99
+ &:hover {
100
+ opacity: 0.8;
101
+ }
102
+
103
+ &:focus-visible {
104
+ outline: 2px solid currentColor;
105
+ outline-offset: 2px;
106
+ }
107
+ }
108
+
109
+ &--fade::before,
110
+ &--fade::after {
111
+ content: '';
112
+ position: absolute;
113
+ top: 0;
114
+ bottom: 0;
115
+ width: clamp(24px, 8%, 120px);
116
+ pointer-events: none;
117
+ z-index: 10;
118
+ }
119
+
120
+ &--fade::before {
121
+ // rtl-ok: paired with the physical `linear-gradient(to right, …)` below, which has no logical form
122
+ left: 0;
123
+ background: linear-gradient(
124
+ to right,
125
+ var(--wr-marquee-fade-color, var(--wr-marquee-fade-color-auto)) 0%,
126
+ rgba(0, 0, 0, 0) 100%
127
+ );
128
+ }
129
+
130
+ &--fade::after {
131
+ // rtl-ok: paired with the physical `linear-gradient(to left, …)` below, which has no logical form
132
+ right: 0;
133
+ background: linear-gradient(
134
+ to left,
135
+ var(--wr-marquee-fade-color, var(--wr-marquee-fade-color-auto)) 0%,
136
+ rgba(0, 0, 0, 0) 100%
137
+ );
138
+ }
139
+
140
+ @media (prefers-reduced-motion: reduce) {
141
+ .wr-marquee__track {
142
+ transform: translate3d(0, 0, 0) !important;
143
+ }
144
+
145
+ .wr-marquee__item img,
146
+ .wr-marquee__node {
147
+ transition: none !important;
148
+ }
149
+ }
150
+ }
@@ -0,0 +1,243 @@
1
+ @use 'sass:list';
2
+ @use 'sass:map';
3
+
4
+ // --- Anchored-panel arrow ----------------------------------------------------
5
+ //
6
+ // A small square rotated 45°, half tucked under the panel so only the tip shows.
7
+ // Shared by every overlay that points AT its trigger: `wr-popover`, its tooltip
8
+ // mode, and `wr-popconfirm`.
9
+ //
10
+ // **Why this lives in `ngwr/overlay` and not in `ngwr/theme`.** `theme/styles`
11
+ // is the token layer plus mixins any element can use — `smooth-br`,
12
+ // `touch-target`, `focus-ring`. This is not one of those. It only means anything
13
+ // against a CDK pane that carries a `--<placement>` modifier written by
14
+ // `wrPopoverPositions()` / a directive's `panelClass`, and the eight-to-twelve
15
+ // placement names it keys off are `WR_POPOVER_POSITIONS`. That is the overlay
16
+ // layer's vocabulary, and `overlay/styles` is already where the cross-overlay
17
+ // presentation lives (`.wr-overlay-sheet`, `.wr-overlay-backdrop`). Promoting it
18
+ // to `ngwr/theme` would advertise it to every component in the catalog as
19
+ // something general, which it is not.
20
+ //
21
+ // It is deliberately NOT `@forward`ed from `overlay/styles/_index.scss`, so
22
+ // `@use 'ngwr/overlay'` gains no new public API and this file emits no CSS of
23
+ // its own — a component `@use`s it by relative path and pays only for the rules
24
+ // its own `anchored-arrow()` call generates.
25
+
26
+ /// Side of the square's box. Half of it shows; the rest is under the panel.
27
+ $size: 6px;
28
+ $half: 3px;
29
+
30
+ /// Distance from the panel corner for the `-start` / `-end` variants.
31
+ $inset: 0.625rem;
32
+
33
+ /// Every placement an anchored panel can take, mapped to
34
+ /// (which panel edge the arrow hangs off, where along that edge it sits).
35
+ ///
36
+ /// A `--top` pane means the panel sits ABOVE the trigger, so the arrow hangs off
37
+ /// the panel's BOTTOM edge.
38
+ $placements: (
39
+ top: (
40
+ bottom,
41
+ center,
42
+ ),
43
+ top-start: (
44
+ bottom,
45
+ start,
46
+ ),
47
+ top-end: (
48
+ bottom,
49
+ end,
50
+ ),
51
+ bottom: (
52
+ top,
53
+ center,
54
+ ),
55
+ bottom-start: (
56
+ top,
57
+ start,
58
+ ),
59
+ bottom-end: (
60
+ top,
61
+ end,
62
+ ),
63
+ left: (
64
+ right,
65
+ center,
66
+ ),
67
+ left-start: (
68
+ right,
69
+ start,
70
+ ),
71
+ left-end: (
72
+ right,
73
+ end,
74
+ ),
75
+ right: (
76
+ left,
77
+ center,
78
+ ),
79
+ right-start: (
80
+ left,
81
+ start,
82
+ ),
83
+ right-end: (
84
+ left,
85
+ end,
86
+ ),
87
+ );
88
+
89
+ /// Positions the arrow against `$edge`, offset outwards by `$pull`.
90
+ ///
91
+ /// `left` / `right` name the panel edge in LTR terms only. Every side-anchored
92
+ /// and `-start` / `-end` placement is expressed as CDK `originX: start | end` —
93
+ /// plain `top` / `bottom` use `center`, which mirrors to itself — and CDK
94
+ /// resolves start / end against `Directionality`. So under `dir="rtl"` the panel
95
+ /// lands on the mirrored side of the trigger while the modifier class keeps its
96
+ /// LTR name, and the arrow has to travel with the panel. Same for the `-start` /
97
+ /// `-end` alignment along a horizontal edge.
98
+ ///
99
+ /// The class names the placement the panel ACTUALLY took, not the requested one,
100
+ /// wherever the caller feeds `withPositions()` a fallback list whose links each
101
+ /// carry their own `panelClass` — so a flip swaps the modifier and this moves the
102
+ /// arrow with it.
103
+ @mixin at($edge, $align, $pull) {
104
+ @if $edge == left {
105
+ inset-inline-start: -$pull;
106
+ } @else if $edge == right {
107
+ inset-inline-end: -$pull;
108
+ } @else {
109
+ #{$edge}: -$pull;
110
+ }
111
+
112
+ @if $edge == bottom or $edge == top {
113
+ @if $align == center {
114
+ // Both halves of the centring pair go logical together, so the arrow
115
+ // stays on the midpoint whichever way the axis runs.
116
+ inset-inline-start: 50%;
117
+ margin-inline-start: -$half;
118
+ } @else if $align == start {
119
+ inset-inline-start: $inset;
120
+ } @else {
121
+ inset-inline-end: $inset;
122
+ }
123
+ } @else {
124
+ @if $align == center {
125
+ top: 50%;
126
+ margin-top: -$half;
127
+ } @else if $align == start {
128
+ top: $inset;
129
+ } @else {
130
+ bottom: $inset;
131
+ }
132
+ }
133
+ }
134
+
135
+ /// The two faces of the rotated square that stay visible outside the panel.
136
+ ///
137
+ /// These stay physical, and it is not an oversight. Which two borders paint is
138
+ /// decided by `transform: rotate(45deg)`, not by reading order: the rotation
139
+ /// turns the right border into the down-right face and the bottom one into the
140
+ /// down-left face, so `right + bottom` is what outlines a tip pointing DOWN.
141
+ /// Swapping only the inline half would paint two faces that are tucked under
142
+ /// the panel. A mirrored arrow needs the rotation mirrored as well — more than
143
+ /// a property rewrite, so it is left for the RTL pass that owns the TS side.
144
+ @mixin faces($edge, $color) {
145
+ @if $edge == bottom {
146
+ // rtl-ok: down-right face of a 45°-rotated square — fixed by the rotation
147
+ border-right: 1px solid $color;
148
+ border-bottom: 1px solid $color;
149
+ } @else if $edge == top {
150
+ // rtl-ok: up-left face of a 45°-rotated square — fixed by the rotation
151
+ border-left: 1px solid $color;
152
+ border-top: 1px solid $color;
153
+ } @else if $edge == right {
154
+ border-top: 1px solid $color;
155
+ // rtl-ok: down-right face of a 45°-rotated square — fixed by the rotation
156
+ border-right: 1px solid $color;
157
+ } @else {
158
+ border-bottom: 1px solid $color;
159
+ // rtl-ok: up-left face of a 45°-rotated square — fixed by the rotation
160
+ border-left: 1px solid $color;
161
+ }
162
+ }
163
+
164
+ /// Draws the arrow for an anchored overlay, at every placement it can take.
165
+ ///
166
+ /// @param {String} $pane - the CDK pane class the directive sets, without the
167
+ /// modifier: `.wr-popover-overlay`, `.wr-popconfirm-overlay`.
168
+ /// @param {String} $panel - selector for the painted surface INSIDE the pane,
169
+ /// relative to it: `> *` where the pane wraps an arbitrary child,
170
+ /// `> .wr-popconfirm` / `.wr-tooltip` where it has a known one. The arrow is
171
+ /// that element's `::after`, so this is also the element made `position:
172
+ /// relative`.
173
+ /// @param {*} $background - fill for the square; match the panel's own so the
174
+ /// two read as one shape. A `var()` is fine and preferred.
175
+ /// @param {*} $border - the panel's border colour, or `null` for a panel with no
176
+ /// border. When set, the two outward faces are painted so the outline reads as
177
+ /// continuous, and the square is pulled one extra pixel outwards so its own
178
+ /// border lines up flush with the panel's instead of leaving the panel border
179
+ /// showing across the arrow's base. A borderless panel has nothing to line up
180
+ /// with, hence the smaller pull.
181
+ /// @param {Bool} $inert - `true` drops the arrow out of hit-testing. For a
182
+ /// tooltip, whose arrow overlaps the very control the tooltip describes, so a
183
+ /// hittable arrow eats clicks meant for it.
184
+ /// @param {List} $placements-used - which placements to emit, defaulting to all
185
+ /// twelve. A component whose position input offers four should pass four
186
+ /// rather than shipping eight rules that can never match.
187
+ @mixin anchored-arrow($pane, $panel, $background, $border: null, $inert: false, $placements-used: map.keys($placements)) {
188
+ #{$pane} {
189
+ #{$panel} {
190
+ // Containing block for the arrow.
191
+ position: relative;
192
+
193
+ &::after {
194
+ content: '';
195
+ position: absolute;
196
+ width: $size;
197
+ height: $size;
198
+ background: $background;
199
+ transform: rotate(45deg);
200
+
201
+ @if $inert {
202
+ pointer-events: none;
203
+ }
204
+ }
205
+ }
206
+
207
+ // Responsive bottom-sheet mode detaches the panel from its trigger and docks
208
+ // it to the bottom of the screen, so there is nothing left to point at.
209
+ // Emitted for every caller, not only the ones that support sheets today: the
210
+ // arrow is what would be wrong there, so the arrow is what should know.
211
+ &.wr-overlay-sheet #{$panel}::after {
212
+ content: none;
213
+ }
214
+ }
215
+
216
+ @each $placement in $placements-used {
217
+ $spec: map.get($placements, $placement);
218
+
219
+ @if $spec == null {
220
+ @error 'wr arrow: unknown placement `#{$placement}` — expected one of #{map.keys($placements)}.';
221
+ }
222
+
223
+ $edge: list.nth($spec, 1);
224
+ $align: list.nth($spec, 2);
225
+
226
+ // A bordered panel pulls one extra pixel, so the square's own border lines
227
+ // up flush with the panel's instead of leaving the panel border showing
228
+ // across the arrow's base. A borderless one has nothing to line up with.
229
+ $pull: $half;
230
+
231
+ @if $border != null {
232
+ $pull: $half + 1px;
233
+ }
234
+
235
+ #{$pane}--#{$placement} #{$panel}::after {
236
+ @include at($edge, $align, $pull);
237
+
238
+ @if $border != null {
239
+ @include faces($edge, $border);
240
+ }
241
+ }
242
+ }
243
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngwr",
3
- "version": "12.1.0",
3
+ "version": "13.0.0",
4
4
  "bin": {
5
5
  "ngwr-mcp": "./mcp/server.js"
6
6
  },
@@ -1,4 +1,5 @@
1
1
  @use '../../theme/styles' as theme;
2
+ @use '../../overlay/styles/arrow';
2
3
 
3
4
  .wr-popconfirm-overlay {
4
5
  > .wr-popconfirm {
@@ -13,6 +14,7 @@
13
14
  color: var(--wr-color-on-surface);
14
15
  font-family: var(--wr-font-family-base);
15
16
  animation: wr-overlay-in var(--wr-overlay-duration) var(--wr-overlay-ease);
17
+ // rtl-ok: scale-in growth corner — `transform-origin` takes no logical keywords
16
18
  transform-origin: top left;
17
19
  }
18
20
  }
@@ -30,3 +32,18 @@
30
32
  gap: 0.375rem;
31
33
  }
32
34
  }
35
+
36
+ // The arrow that ties the panel to the control it is asking about — the same one
37
+ // `wr-popover` draws, from the same mixin, because the two are the same kind of
38
+ // anchored non-modal panel and a second copy of the geometry would drift.
39
+ //
40
+ // Four placements, not twelve: `WrPopconfirmPosition` is `top | bottom | left |
41
+ // right`, and the eight `-start` / `-end` rules would be selectors that can
42
+ // never match. Widen this list if the input ever grows them.
43
+ @include arrow.anchored-arrow(
44
+ $pane: '.wr-popconfirm-overlay',
45
+ $panel: '> .wr-popconfirm',
46
+ $background: var(--wr-color-surface),
47
+ $border: var(--wr-color-outline),
48
+ $placements-used: (top, bottom, left, right)
49
+ );