ngwr 12.2.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 (174) hide show
  1. package/README.md +11 -1
  2. package/border-glow/border-glow.scss +1 -1
  3. package/border-glow/styles/_index.scss +15 -233
  4. package/border-glow/styles/_rules.scss +228 -0
  5. package/breadcrumbs/breadcrumbs.scss +1 -1
  6. package/breadcrumbs/styles/_index.scss +15 -78
  7. package/breadcrumbs/styles/_rules.scss +84 -0
  8. package/card/card.scss +1 -1
  9. package/card/styles/_index.scss +15 -96
  10. package/card/styles/_rules.scss +96 -0
  11. package/cascader/cascader.scss +1 -1
  12. package/cascader/styles/_index.scss +15 -244
  13. package/cascader/styles/_rules.scss +261 -0
  14. package/checkbox/styles/_index.scss +7 -0
  15. package/circular-text/circular-text.scss +1 -1
  16. package/circular-text/styles/_index.scss +15 -63
  17. package/circular-text/styles/_rules.scss +58 -0
  18. package/color-picker/styles/_index.scss +8 -0
  19. package/drag-drop/sortable-list.scss +1 -1
  20. package/drag-drop/styles/_index.scss +14 -143
  21. package/drag-drop/styles/_rules.scss +151 -0
  22. package/falling-text/falling-text.scss +1 -1
  23. package/falling-text/styles/_index.scss +15 -36
  24. package/falling-text/styles/_rules.scss +31 -0
  25. package/fesm2022/ngwr-border-glow.mjs +2 -2
  26. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  27. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  28. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  29. package/fesm2022/ngwr-card.mjs +2 -2
  30. package/fesm2022/ngwr-card.mjs.map +1 -1
  31. package/fesm2022/ngwr-cascader.mjs +27 -9
  32. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  33. package/fesm2022/ngwr-checkbox.mjs +86 -8
  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 +57 -7
  38. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  39. package/fesm2022/ngwr-date-picker.mjs +8 -0
  40. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  41. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  42. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  43. package/fesm2022/ngwr-falling-text.mjs +2 -2
  44. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  45. package/fesm2022/ngwr-file-upload.mjs +29 -8
  46. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  47. package/fesm2022/ngwr-form.mjs +48 -1
  48. package/fesm2022/ngwr-form.mjs.map +1 -1
  49. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  50. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  51. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  52. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  53. package/fesm2022/ngwr-input-otp.mjs +41 -3
  54. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  55. package/fesm2022/ngwr-knob.mjs +17 -2
  56. package/fesm2022/ngwr-knob.mjs.map +1 -1
  57. package/fesm2022/ngwr-lightbox.mjs +2 -2
  58. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  59. package/fesm2022/ngwr-list.mjs +2 -2
  60. package/fesm2022/ngwr-list.mjs.map +1 -1
  61. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  62. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  63. package/fesm2022/ngwr-marquee.mjs +2 -2
  64. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  65. package/fesm2022/ngwr-pagination.mjs +1 -1
  66. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  67. package/fesm2022/ngwr-radio.mjs +63 -8
  68. package/fesm2022/ngwr-radio.mjs.map +1 -1
  69. package/fesm2022/ngwr-rating.mjs +17 -2
  70. package/fesm2022/ngwr-rating.mjs.map +1 -1
  71. package/fesm2022/ngwr-segmented.mjs +22 -3
  72. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  73. package/fesm2022/ngwr-select.mjs +46 -12
  74. package/fesm2022/ngwr-select.mjs.map +1 -1
  75. package/fesm2022/ngwr-shiny-text.mjs +2 -2
  76. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  77. package/fesm2022/ngwr-slider.mjs +21 -6
  78. package/fesm2022/ngwr-slider.mjs.map +1 -1
  79. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  80. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  81. package/fesm2022/ngwr-star-border.mjs +2 -2
  82. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  83. package/fesm2022/ngwr-switch.mjs +44 -4
  84. package/fesm2022/ngwr-switch.mjs.map +1 -1
  85. package/fesm2022/ngwr-table.mjs +1 -1
  86. package/fesm2022/ngwr-table.mjs.map +1 -1
  87. package/fesm2022/ngwr-textarea.mjs +5 -2
  88. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  89. package/fesm2022/ngwr-theme.mjs +41 -1
  90. package/fesm2022/ngwr-theme.mjs.map +1 -1
  91. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  92. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  93. package/fesm2022/ngwr-transfer.mjs +38 -6
  94. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  95. package/fesm2022/ngwr-tree.mjs +33 -7
  96. package/fesm2022/ngwr-tree.mjs.map +1 -1
  97. package/fesm2022/ngwr-typewriter.mjs +2 -2
  98. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  99. package/fesm2022/ngwr-version.mjs +1 -1
  100. package/fesm2022/ngwr-version.mjs.map +1 -1
  101. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  102. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  103. package/fesm2022/ngwr-waves.mjs +2 -2
  104. package/fesm2022/ngwr-waves.mjs.map +1 -1
  105. package/file-upload/styles/_index.scss +6 -0
  106. package/glitch-text/glitch-text.scss +1 -1
  107. package/glitch-text/styles/_index.scss +14 -164
  108. package/glitch-text/styles/_rules.scss +160 -0
  109. package/gradient-text/gradient-text.scss +1 -1
  110. package/gradient-text/styles/_index.scss +15 -118
  111. package/gradient-text/styles/_rules.scss +113 -0
  112. package/input/styles/_index.scss +13 -0
  113. package/input-otp/styles/_index.scss +8 -0
  114. package/lightbox/lightbox.scss +1 -1
  115. package/lightbox/styles/_index.scss +15 -191
  116. package/lightbox/styles/_rules.scss +198 -0
  117. package/list/list.scss +1 -1
  118. package/list/styles/_index.scss +15 -101
  119. package/list/styles/_rules.scss +108 -0
  120. package/llms-full.txt +3 -3
  121. package/loading-bar/loading-bar.scss +1 -1
  122. package/loading-bar/styles/_index.scss +15 -33
  123. package/loading-bar/styles/_rules.scss +28 -0
  124. package/marquee/marquee.scss +1 -1
  125. package/marquee/styles/_index.scss +15 -155
  126. package/marquee/styles/_rules.scss +150 -0
  127. package/package.json +1 -1
  128. package/segmented/styles/_index.scss +8 -0
  129. package/select/styles/_index.scss +17 -1
  130. package/shiny-text/shiny-text.scss +1 -1
  131. package/shiny-text/styles/_index.scss +14 -105
  132. package/shiny-text/styles/_rules.scss +101 -0
  133. package/slider/styles/_index.scss +8 -0
  134. package/spotlight-card/spotlight-card.scss +1 -1
  135. package/spotlight-card/styles/_index.scss +15 -52
  136. package/spotlight-card/styles/_rules.scss +47 -0
  137. package/star-border/star-border.scss +1 -1
  138. package/star-border/styles/_index.scss +15 -125
  139. package/star-border/styles/_rules.scss +120 -0
  140. package/switch/styles/_index.scss +7 -0
  141. package/theme/styles/_dark.scss +81 -4
  142. package/theme/styles/_index.scss +1 -0
  143. package/theme/styles/_motion.scss +94 -0
  144. package/tilt-card/styles/_index.scss +15 -45
  145. package/tilt-card/styles/_rules.scss +40 -0
  146. package/tilt-card/tilt-card.scss +1 -1
  147. package/tree/styles/_index.scss +15 -1
  148. package/types/ngwr-cascader.d.ts +17 -1
  149. package/types/ngwr-checkbox.d.ts +51 -3
  150. package/types/ngwr-color-picker.d.ts +19 -1
  151. package/types/ngwr-file-upload.d.ts +18 -1
  152. package/types/ngwr-form.d.ts +51 -2
  153. package/types/ngwr-input-otp.d.ts +23 -1
  154. package/types/ngwr-knob.d.ts +14 -0
  155. package/types/ngwr-radio.d.ts +37 -2
  156. package/types/ngwr-rating.d.ts +14 -0
  157. package/types/ngwr-segmented.d.ts +18 -1
  158. package/types/ngwr-select.d.ts +17 -1
  159. package/types/ngwr-slider.d.ts +14 -1
  160. package/types/ngwr-switch.d.ts +26 -2
  161. package/types/ngwr-textarea.d.ts +3 -0
  162. package/types/ngwr-theme.d.ts +24 -0
  163. package/types/ngwr-transfer.d.ts +17 -1
  164. package/types/ngwr-tree.d.ts +21 -1
  165. package/types/ngwr-version.d.ts +1 -1
  166. package/typewriter/styles/_index.scss +15 -38
  167. package/typewriter/styles/_rules.scss +33 -0
  168. package/typewriter/typewriter.scss +1 -1
  169. package/virtual-scroll/styles/_index.scss +15 -32
  170. package/virtual-scroll/styles/_rules.scss +27 -0
  171. package/virtual-scroll/virtual-scroll.scss +1 -1
  172. package/waves/styles/_index.scss +15 -50
  173. package/waves/styles/_rules.scss +45 -0
  174. package/waves/waves.scss +1 -1
@@ -0,0 +1,261 @@
1
+ // Cascader. The trigger reuses the wr-select look-and-feel; the panel
2
+ // is a horizontal row of columns where each column lists the children
3
+ // of the previously-active node. Picking a leaf commits the path.
4
+
5
+ // `focus` is the one theme partial these rules still load that emits CSS of its
6
+ // own — the shared ring mixin lives in the same file as the baseline
7
+ // `.wr-*:focus-visible` rules, and there is no mixin-only module to take it from.
8
+ // That is ~4 KB of rules identical to the global sheet's, against the ~24 KB token
9
+ // layer the split removes, and it is the honest trade: hand-rolling the three
10
+ // declarations here is what the shared mixin exists to prevent.
11
+ @use '../../theme/styles/focus';
12
+
13
+ .wr-cascader {
14
+ --wr-cascader-color: var(--wr-color-on-surface);
15
+ --wr-cascader-bg: var(--wr-color-surface);
16
+ --wr-cascader-border: var(--wr-color-outline);
17
+ --wr-cascader-radius: var(--wr-control-radius-md);
18
+ --wr-cascader-padding-y: var(--wr-control-padding-y-md);
19
+ --wr-cascader-padding-x: var(--wr-control-padding-x-md);
20
+ --wr-cascader-font-size: var(--wr-control-font-size-md);
21
+ --wr-cascader-line-height: var(--wr-control-line-height-md);
22
+ --wr-cascader-col-width: 12rem;
23
+ --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.
28
+ --wr-cascader-min-width: 12rem;
29
+
30
+ display: inline-flex;
31
+ vertical-align: middle;
32
+
33
+ &--disabled {
34
+ --wr-cascader-color: var(--wr-color-on-surface-muted);
35
+ --wr-cascader-bg: var(--wr-color-fill);
36
+ }
37
+
38
+ // Sizes — trigger on the control contract (sm 22 / md 30 / lg 36).
39
+ &--sm {
40
+ --wr-cascader-radius: var(--wr-control-radius-sm);
41
+ --wr-cascader-padding-y: var(--wr-control-padding-y-sm);
42
+ --wr-cascader-padding-x: var(--wr-control-padding-x-sm);
43
+ --wr-cascader-font-size: var(--wr-control-font-size-sm);
44
+ --wr-cascader-line-height: var(--wr-control-line-height-sm);
45
+ }
46
+
47
+ &--lg {
48
+ --wr-cascader-radius: var(--wr-control-radius-lg);
49
+ --wr-cascader-padding-y: var(--wr-control-padding-y-lg);
50
+ --wr-cascader-padding-x: var(--wr-control-padding-x-lg);
51
+ --wr-cascader-font-size: var(--wr-control-font-size-lg);
52
+ --wr-cascader-line-height: var(--wr-control-line-height-lg);
53
+ }
54
+
55
+ &__trigger {
56
+ display: inline-flex;
57
+ align-items: center;
58
+ gap: 0.5rem;
59
+ width: 100%;
60
+ min-width: var(--wr-cascader-min-width);
61
+ appearance: none;
62
+ background: var(--wr-cascader-bg);
63
+ color: var(--wr-cascader-color);
64
+ border: 1px solid var(--wr-cascader-border);
65
+ border-radius: var(--wr-cascader-radius);
66
+ // Density-multiplied like select / input / textarea / button: the trigger
67
+ // sources the same `--wr-control-padding-*` contract they do, so without
68
+ // the multiplier it held its md height (30px) while its neighbours grew —
69
+ // measured at 35.59px for input / select under `touch`.
70
+ padding: calc(var(--wr-cascader-padding-y) * var(--wr-density-y, 1))
71
+ calc(var(--wr-cascader-padding-x) * var(--wr-density-x, 1));
72
+ font-family: var(--wr-font-family-base);
73
+ font-size: var(--wr-cascader-font-size);
74
+ line-height: var(--wr-cascader-line-height);
75
+ cursor: pointer;
76
+ text-align: start;
77
+ transition:
78
+ border-color var(--wr-transition-base),
79
+ box-shadow var(--wr-transition-base);
80
+
81
+ &:focus-visible {
82
+ border-color: var(--wr-color-primary);
83
+ @include focus.focus-ring;
84
+ }
85
+
86
+ &:disabled {
87
+ cursor: not-allowed;
88
+ }
89
+ }
90
+
91
+ // A read-only trigger still takes focus and still shows its path, so it keeps
92
+ // the visual and only stops inviting the click that would open the panel.
93
+ &--readonly &__trigger {
94
+ cursor: default;
95
+ }
96
+
97
+ &--open &__trigger {
98
+ border-color: var(--wr-color-primary);
99
+ box-shadow: 0 0 0 3px rgba(var(--wr-color-primary-rgb), 0.15);
100
+ }
101
+
102
+ &__value,
103
+ &__placeholder {
104
+ flex: 1 1 auto;
105
+ overflow: hidden;
106
+ text-overflow: ellipsis;
107
+ white-space: nowrap;
108
+ }
109
+
110
+ &__placeholder {
111
+ color: var(--wr-color-text-muted);
112
+ }
113
+
114
+ &__chevron {
115
+ --wr-icon-size: 1rem;
116
+ flex: 0 0 auto;
117
+ color: var(--wr-color-on-surface-muted);
118
+ transition: transform var(--wr-transition-base);
119
+ }
120
+
121
+ &--open &__chevron {
122
+ transform: rotate(180deg);
123
+ }
124
+
125
+ &__clear {
126
+ --wr-icon-size: 0.875rem;
127
+ display: inline-flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ width: 1.125rem;
131
+ height: 1.125rem;
132
+ border-radius: 999px;
133
+ color: var(--wr-color-on-surface-muted);
134
+ cursor: pointer;
135
+ transition:
136
+ background 0.12s ease,
137
+ color 0.12s ease;
138
+
139
+ &:hover {
140
+ background: rgba(var(--wr-color-on-surface-rgb), 0.06);
141
+ color: var(--wr-color-on-surface);
142
+ }
143
+ }
144
+ }
145
+
146
+ .wr-cascader-overlay {
147
+ padding-top: 0.25rem;
148
+ }
149
+
150
+ .wr-cascader-panel {
151
+ // Option sizing — mirrored from the trigger size (panel is portaled, so it
152
+ // can't inherit the host size class). Default md.
153
+ --wr-cascader-opt-font: var(--wr-control-font-size-md);
154
+ --wr-cascader-opt-py: 0.5rem;
155
+
156
+ display: flex;
157
+ background: var(--wr-color-surface);
158
+ border: 1px solid var(--wr-color-outline);
159
+ border-radius: var(--wr-border-radius-base);
160
+ box-shadow: var(--wr-shadow-overlay);
161
+ font-family: var(--wr-font-family-base);
162
+ font-size: var(--wr-cascader-opt-font);
163
+ overflow: hidden;
164
+
165
+ &--sm {
166
+ --wr-cascader-opt-font: var(--wr-control-font-size-sm);
167
+ --wr-cascader-opt-py: 0.375rem;
168
+ }
169
+
170
+ &--lg {
171
+ --wr-cascader-opt-font: var(--wr-control-font-size-lg);
172
+ --wr-cascader-opt-py: 0.625rem;
173
+ }
174
+
175
+ .wr-cascader__col {
176
+ list-style: none;
177
+ margin: 0;
178
+ // Inset padding so options read as rounded pills, matching the select panel.
179
+ padding: 0.25rem;
180
+ width: var(--wr-cascader-col-width, 12rem);
181
+ max-height: var(--wr-cascader-max-height, 16rem);
182
+ overflow-y: auto;
183
+ display: flex;
184
+ flex-direction: column;
185
+ gap: 0.125rem;
186
+
187
+ + .wr-cascader__col {
188
+ border-inline-start: 1px solid var(--wr-color-outline);
189
+ }
190
+ }
191
+
192
+ // Options mirror .wr-option (rounded pill, soft primary tint when active).
193
+ .wr-cascader__opt {
194
+ display: flex;
195
+ align-items: center;
196
+ gap: 0.5rem;
197
+ padding: var(--wr-cascader-opt-py) 0.625rem;
198
+ border-radius: var(--wr-border-radius-sm);
199
+ color: var(--wr-color-on-surface);
200
+ cursor: pointer;
201
+ transition: background var(--wr-transition-short);
202
+
203
+ &:hover {
204
+ background: var(--wr-color-hover);
205
+ }
206
+
207
+ &--active {
208
+ background: var(--wr-color-primary-soft);
209
+ // Text on the intent's own `-soft` tint, which is exactly what `-ink` is
210
+ // calibrated against. Bare measured 4.17:1 light / 3.65:1 dark.
211
+ color: var(--wr-color-primary-ink);
212
+ font-weight: 500;
213
+ }
214
+
215
+ &--disabled {
216
+ color: var(--wr-color-on-surface-muted);
217
+ cursor: not-allowed;
218
+ opacity: var(--wr-disabled-opacity);
219
+
220
+ &:hover {
221
+ background: transparent;
222
+ }
223
+ }
224
+ }
225
+
226
+ .wr-cascader__opt-label {
227
+ flex: 1 1 auto;
228
+ overflow: hidden;
229
+ text-overflow: ellipsis;
230
+ white-space: nowrap;
231
+ }
232
+
233
+ .wr-cascader__opt-arrow {
234
+ --wr-icon-size: 0.875rem;
235
+ flex: 0 0 auto;
236
+ color: var(--wr-color-on-surface-muted);
237
+ }
238
+
239
+ // The panel is a flex row, so its columns cascade toward the inline end —
240
+ // leftward under `dir="rtl"`. The branch arrow is drawn pointing physically
241
+ // right, so turn it around with them, the way the carousel's arrows do.
242
+ [dir='rtl'] & .wr-cascader__opt-arrow {
243
+ transform: scaleX(-1);
244
+ }
245
+ }
246
+
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.
250
+ @media (pointer: coarse) {
251
+ .wr-cascader__clear {
252
+ --wr-icon-size: 1.125rem;
253
+ width: 2rem;
254
+ height: 2rem;
255
+ }
256
+
257
+ .wr-cascader-panel .wr-cascader__opt {
258
+ padding-top: 0.75rem;
259
+ padding-bottom: 0.75rem;
260
+ }
261
+ }
@@ -120,6 +120,13 @@
120
120
  }
121
121
  }
122
122
 
123
+ // A read-only box still takes focus and still submits its value, so it keeps
124
+ // the full visual and only stops inviting the click — dimming it would say
125
+ // "disabled", which is the other state. Matches `wr-rating--readonly`.
126
+ &--readonly &__label {
127
+ cursor: default;
128
+ }
129
+
123
130
  &--disabled {
124
131
  --wr-checkbox-color: var(--wr-color-on-surface-muted);
125
132
  pointer-events: none;
@@ -1 +1 @@
1
- @forward './styles';
1
+ @forward './styles/rules';
@@ -1,63 +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
- // Circular text (reactbits port). Each char is absolutely positioned at
7
- // the spinner's centre, then transformed `rotate() translateY(-radius)`
8
- // so it lands on the perimeter of a circle of constant radius. The host
9
- // itself is static; the inner `__spin` element drives the rotation via
10
- // the Web Animations API (see component for the why). Hover-mode `scale`
11
- // lives on the host so it never fights the rotation.
12
-
13
- .wr-circular-text {
14
- --wr-circular-text-size: 12rem;
15
- --wr-circular-text-radius: calc(var(--wr-circular-text-size) / 2);
16
-
17
- position: relative;
18
- display: inline-block;
19
- width: var(--wr-circular-text-size);
20
- height: var(--wr-circular-text-size);
21
- border-radius: 50%;
22
- font-weight: 700;
23
- text-align: center;
24
- user-select: none;
25
- transition: transform 0.6s var(--wr-ease-spring);
26
-
27
- // The accessible copy of the string — the ring itself is `aria-hidden`.
28
- &__sr-only {
29
- position: absolute;
30
- width: 1px;
31
- height: 1px;
32
- overflow: hidden;
33
- clip: rect(0 0 0 0);
34
- clip-path: inset(50%);
35
- white-space: nowrap;
36
- }
37
-
38
- &__spin {
39
- position: absolute;
40
- inset: 0;
41
- will-change: transform;
42
- }
43
-
44
- &__char {
45
- position: absolute;
46
- top: 50%;
47
- // rtl-ok: centred on the spinner's midpoint by a physical margin-left/-top pair plus a per-char translateY()
48
- left: 50%;
49
- display: inline-block;
50
- // Pre-shift by -50% so the char's centre sits at the spinner centre
51
- // before the per-char `rotate translateY(-radius)` runs.
52
- // rtl-ok: the negative half of the `left: 50%` centring pair, symmetric with `margin-top`
53
- margin-left: -0.5em;
54
- margin-top: -0.5em;
55
- line-height: 1;
56
- }
57
-
58
- // Bonkers — scale the whole host on hover (rotation lives on inner,
59
- // so the transforms never fight each other).
60
- &--bonkers:hover {
61
- transform: scale(0.8);
62
- }
63
- }
1
+ // Public Sass entry for `@use 'ngwr/circular-text'`.
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
+ // `circular-text.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. `circular-text.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,58 @@
1
+ // Circular text (reactbits port). Each char is absolutely positioned at
2
+ // the spinner's centre, then transformed `rotate() translateY(-radius)`
3
+ // so it lands on the perimeter of a circle of constant radius. The host
4
+ // itself is static; the inner `__spin` element drives the rotation via
5
+ // the Web Animations API (see component for the why). Hover-mode `scale`
6
+ // lives on the host so it never fights the rotation.
7
+
8
+ .wr-circular-text {
9
+ --wr-circular-text-size: 12rem;
10
+ --wr-circular-text-radius: calc(var(--wr-circular-text-size) / 2);
11
+
12
+ position: relative;
13
+ display: inline-block;
14
+ width: var(--wr-circular-text-size);
15
+ height: var(--wr-circular-text-size);
16
+ border-radius: 50%;
17
+ font-weight: 700;
18
+ text-align: center;
19
+ user-select: none;
20
+ transition: transform 0.6s var(--wr-ease-spring);
21
+
22
+ // The accessible copy of the string — the ring itself is `aria-hidden`.
23
+ &__sr-only {
24
+ position: absolute;
25
+ width: 1px;
26
+ height: 1px;
27
+ overflow: hidden;
28
+ clip: rect(0 0 0 0);
29
+ clip-path: inset(50%);
30
+ white-space: nowrap;
31
+ }
32
+
33
+ &__spin {
34
+ position: absolute;
35
+ inset: 0;
36
+ will-change: transform;
37
+ }
38
+
39
+ &__char {
40
+ position: absolute;
41
+ top: 50%;
42
+ // rtl-ok: centred on the spinner's midpoint by a physical margin-left/-top pair plus a per-char translateY()
43
+ left: 50%;
44
+ display: inline-block;
45
+ // Pre-shift by -50% so the char's centre sits at the spinner centre
46
+ // before the per-char `rotate translateY(-radius)` runs.
47
+ // rtl-ok: the negative half of the `left: 50%` centring pair, symmetric with `margin-top`
48
+ margin-left: -0.5em;
49
+ margin-top: -0.5em;
50
+ line-height: 1;
51
+ }
52
+
53
+ // Bonkers — scale the whole host on hover (rotation lives on inner,
54
+ // so the transforms never fight each other).
55
+ &--bonkers:hover {
56
+ transform: scale(0.8);
57
+ }
58
+ }
@@ -251,6 +251,14 @@
251
251
  }
252
252
  }
253
253
 
254
+ // A read-only picker still takes focus and still announces its colour, so it
255
+ // keeps the visual and only stops inviting the drag — `crosshair` / `ew-resize`
256
+ // on a surface that cannot move is the part that looks broken.
257
+ &--readonly &__sv,
258
+ &--readonly &__slider {
259
+ cursor: default;
260
+ }
261
+
254
262
  &--disabled {
255
263
  pointer-events: none;
256
264
  opacity: var(--wr-disabled-opacity);
@@ -1 +1 @@
1
- @forward './styles';
1
+ @forward './styles/rules';
@@ -1,144 +1,15 @@
1
- @use '../../theme/styles' as theme;
2
-
3
- // Drag-to-reorder list. Visual chrome lives here; the layout + drop
4
- // mechanics come from CDK's `cdkDropList` / `cdkDrag` directives.
1
+ // Public Sass entry for `@use 'ngwr/drag-drop'`.
5
2
  //
6
- // CDK adds these classes during a drag:
7
- // .cdk-drag-preview — floating preview that follows the cursor
8
- // .cdk-drag-placeholder — empty slot left at the source position
9
- // .cdk-drag-animating — in the post-drop settle animation
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.
14
-
15
- .wr-sortable-list {
16
- display: block;
17
-
18
- &__list {
19
- display: flex;
20
- flex-direction: column;
21
- // Row spacing belongs to the list, not the row templates — margins
22
- // inside a row get measured into the drag preview and read as a
23
- // white rim around the floating card.
24
- gap: var(--wr-sortable-list-gap, 0.5rem);
25
- }
26
-
27
- &__item {
28
- cursor: grab;
29
- user-select: none;
30
- // No transform transition here — the floating preview clones this
31
- // class, and animating transform makes it chase the cursor 180ms
32
- // behind. Sibling shuffle/settle transitions are scoped below.
33
- transition: box-shadow 0.18s ease;
34
-
35
- &.cdk-drag-disabled {
36
- cursor: default;
37
- }
38
-
39
- &:active {
40
- cursor: grabbing;
41
- }
42
-
43
- // Every row is a tab stop (the keyboard reorder path), so every row needs a
44
- // ring. Included here rather than added to `theme/_focus.scss`, the same
45
- // choice `wr-list` made for its own rows.
46
- &:focus-visible {
47
- @include theme.focus-ring;
48
- }
49
-
50
- // Picked up by the keyboard — the standing counterpart of `:active`, which
51
- // only lasts while a pointer is held down.
52
- &--grabbed {
53
- cursor: grabbing;
54
- box-shadow: 0 6px 12px rgba(var(--wr-color-backdrop-rgb), 0.22);
55
- }
56
- }
57
-
58
- // The key model and the position announcements: read out, never drawn.
59
- &__sr-only {
60
- position: absolute;
61
- width: 1px;
62
- height: 1px;
63
- padding: 0;
64
- margin: -1px;
65
- overflow: hidden;
66
- clip: rect(0, 0, 0, 0);
67
- white-space: nowrap;
68
- border: 0;
69
- }
70
- }
71
-
72
- // Horizontal orientation — the @for stays the same; CDK swaps the
73
- // pointer-position math when `cdkDropListOrientation="horizontal"`.
74
- .wr-sortable-list[orientation='horizontal'] .wr-sortable-list__list,
75
- .wr-sortable-list[data-orientation='horizontal'] .wr-sortable-list__list {
76
- flex-direction: row;
77
- }
78
-
79
- // Drag handle — restricts grab cursor to the handle (the row itself
80
- // stays interactive for clicks / inputs).
81
- .wr-drag-handle {
82
- cursor: grab;
83
- display: inline-flex;
84
- align-items: center;
85
- justify-content: center;
86
- color: rgba(var(--wr-color-on-surface-rgb), 0.45);
87
- transition: color 0.15s ease;
88
-
89
- // Coarse pointers: a 44px grab area around the grip glyph.
90
- @include theme.touch-target;
91
-
92
- &:hover {
93
- color: var(--wr-color-on-surface);
94
- }
95
-
96
- &:active {
97
- cursor: grabbing;
98
- }
99
- }
100
-
101
- // CDK overlays applied by drag-drop
102
-
103
- // The preview is a CLONE of the dragged row that CDK moves to `document.body`,
104
- // so an ancestor selector cannot reach it — but the clone keeps the row's own
105
- // class, which can. Verified on a real drag: the preview lands in `<body>`
106
- // carrying `cdk-drag wr-sortable-list__item cdk-drag-preview`.
107
- .cdk-drag-preview.wr-sortable-list__item {
108
- box-sizing: border-box;
109
- color: var(--wr-color-on-surface);
110
- font-family: var(--wr-font-family-base);
111
- // The preview must track the cursor 1:1 — never animate its transform.
112
- transition: none;
113
- // The lift-off shadow follows the row template's rendered shape
114
- // (drop-shadow, not box-shadow) so the preview box itself never shows
115
- // as a white slab around the card. Backdrop token stays black in dark
116
- // mode — `--wr-color-on-surface-rgb` would flip and glow instead.
117
- filter: drop-shadow(0 8px 12px rgba(var(--wr-color-backdrop-rgb), 0.24))
118
- drop-shadow(0 2px 3px rgba(var(--wr-color-backdrop-rgb), 0.16));
119
- // CDK sets pointer-events to none on the preview; we keep visuals only.
120
- }
121
-
122
- // The placeholder stays in the list, so scoping by ancestor is enough here.
123
- .wr-sortable-list .cdk-drag-placeholder {
124
- opacity: 0.35;
125
- // Subtle dashed outline so users see where the item came from.
126
- background: var(--wr-color-fill-strong);
127
- border-radius: var(--wr-border-radius-base);
128
- outline: 1px dashed rgba(var(--wr-color-on-surface-rgb), 0.25);
129
- outline-offset: -1px;
130
- }
131
-
132
- // Also the preview, not a row in the list: CDK keeps `cdk-drag-preview` on the
133
- // clone and adds `cdk-drag-animating` while it flies back to the drop slot.
134
- // Verified on a real drop — the element carries
135
- // `cdk-drag wr-sortable-list__item cdk-drag-preview cdk-drag-animating` and sits
136
- // in `<body>`. It has to come after the preview rule, which sets
137
- // `transition: none` at the same specificity.
138
- .cdk-drag-animating.wr-sortable-list__item {
139
- transition: transform 0.18s var(--wr-ease-spring);
140
- }
141
-
142
- .wr-sortable-list__list.cdk-drop-list-dragging .wr-sortable-list__item:not(.cdk-drag-placeholder) {
143
- transition: transform 0.18s var(--wr-ease-spring);
144
- }
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
+ // `sortable-list.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. `sortable-list.scss` forwards `_rules`
13
+ // instead, so it carries this component's own CSS and nothing else.
14
+ @use '../../theme/styles';
15
+ @forward 'rules';