ngwr 12.2.0 → 13.0.1

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 (208) 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 +14 -5
  26. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  27. package/fesm2022/ngwr-breadcrumbs.mjs +15 -4
  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-context-menu.mjs +6 -2
  40. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  41. package/fesm2022/ngwr-date-picker.mjs +8 -0
  42. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  43. package/fesm2022/ngwr-dialog.mjs +22 -16
  44. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  45. package/fesm2022/ngwr-directives.mjs +5 -2
  46. package/fesm2022/ngwr-directives.mjs.map +1 -1
  47. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  48. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  49. package/fesm2022/ngwr-drawer.mjs +24 -18
  50. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  51. package/fesm2022/ngwr-dropdown.mjs +6 -2
  52. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  53. package/fesm2022/ngwr-falling-text.mjs +2 -2
  54. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  55. package/fesm2022/ngwr-file-upload.mjs +29 -8
  56. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  57. package/fesm2022/ngwr-form.mjs +48 -1
  58. package/fesm2022/ngwr-form.mjs.map +1 -1
  59. package/fesm2022/ngwr-fuzzy-text.mjs +21 -4
  60. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  61. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  62. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  63. package/fesm2022/ngwr-gradient-text.mjs +11 -4
  64. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  65. package/fesm2022/ngwr-icon-adapters-feather.mjs +11 -0
  66. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  67. package/fesm2022/ngwr-icon-adapters-lucide.mjs +22 -2
  68. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  69. package/fesm2022/ngwr-icon.mjs +474 -37
  70. package/fesm2022/ngwr-icon.mjs.map +1 -1
  71. package/fesm2022/ngwr-input-otp.mjs +41 -3
  72. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  73. package/fesm2022/ngwr-knob.mjs +17 -2
  74. package/fesm2022/ngwr-knob.mjs.map +1 -1
  75. package/fesm2022/ngwr-lightbox.mjs +2 -2
  76. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  77. package/fesm2022/ngwr-list.mjs +2 -2
  78. package/fesm2022/ngwr-list.mjs.map +1 -1
  79. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  80. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  81. package/fesm2022/ngwr-markdown.mjs +63 -11
  82. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  83. package/fesm2022/ngwr-marquee.mjs +2 -2
  84. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  85. package/fesm2022/ngwr-overlay.mjs +36 -7
  86. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  87. package/fesm2022/ngwr-pagination.mjs +1 -1
  88. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  89. package/fesm2022/ngwr-qr.mjs +38 -1
  90. package/fesm2022/ngwr-qr.mjs.map +1 -1
  91. package/fesm2022/ngwr-radio.mjs +63 -8
  92. package/fesm2022/ngwr-radio.mjs.map +1 -1
  93. package/fesm2022/ngwr-rating.mjs +17 -2
  94. package/fesm2022/ngwr-rating.mjs.map +1 -1
  95. package/fesm2022/ngwr-segmented.mjs +22 -3
  96. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  97. package/fesm2022/ngwr-select.mjs +46 -12
  98. package/fesm2022/ngwr-select.mjs.map +1 -1
  99. package/fesm2022/ngwr-shiny-text.mjs +12 -5
  100. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  101. package/fesm2022/ngwr-slider.mjs +21 -6
  102. package/fesm2022/ngwr-slider.mjs.map +1 -1
  103. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  104. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  105. package/fesm2022/ngwr-star-border.mjs +2 -2
  106. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  107. package/fesm2022/ngwr-switch.mjs +44 -4
  108. package/fesm2022/ngwr-switch.mjs.map +1 -1
  109. package/fesm2022/ngwr-table.mjs +1 -1
  110. package/fesm2022/ngwr-table.mjs.map +1 -1
  111. package/fesm2022/ngwr-tabs.mjs +6 -2
  112. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  113. package/fesm2022/ngwr-textarea.mjs +5 -2
  114. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  115. package/fesm2022/ngwr-theme.mjs +41 -1
  116. package/fesm2022/ngwr-theme.mjs.map +1 -1
  117. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  118. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  119. package/fesm2022/ngwr-transfer.mjs +38 -6
  120. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  121. package/fesm2022/ngwr-tree.mjs +33 -7
  122. package/fesm2022/ngwr-tree.mjs.map +1 -1
  123. package/fesm2022/ngwr-typewriter.mjs +2 -2
  124. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  125. package/fesm2022/ngwr-utils.mjs +107 -1
  126. package/fesm2022/ngwr-utils.mjs.map +1 -1
  127. package/fesm2022/ngwr-version.mjs +1 -1
  128. package/fesm2022/ngwr-version.mjs.map +1 -1
  129. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  130. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  131. package/fesm2022/ngwr-waves.mjs +2 -2
  132. package/fesm2022/ngwr-waves.mjs.map +1 -1
  133. package/file-upload/styles/_index.scss +6 -0
  134. package/glitch-text/glitch-text.scss +1 -1
  135. package/glitch-text/styles/_index.scss +14 -164
  136. package/glitch-text/styles/_rules.scss +160 -0
  137. package/gradient-text/gradient-text.scss +1 -1
  138. package/gradient-text/styles/_index.scss +15 -118
  139. package/gradient-text/styles/_rules.scss +113 -0
  140. package/input/styles/_index.scss +13 -0
  141. package/input-otp/styles/_index.scss +8 -0
  142. package/lightbox/lightbox.scss +1 -1
  143. package/lightbox/styles/_index.scss +15 -191
  144. package/lightbox/styles/_rules.scss +198 -0
  145. package/list/list.scss +1 -1
  146. package/list/styles/_index.scss +15 -101
  147. package/list/styles/_rules.scss +108 -0
  148. package/llms-full.txt +4 -4
  149. package/loading-bar/loading-bar.scss +1 -1
  150. package/loading-bar/styles/_index.scss +15 -33
  151. package/loading-bar/styles/_rules.scss +28 -0
  152. package/marquee/marquee.scss +1 -1
  153. package/marquee/styles/_index.scss +15 -155
  154. package/marquee/styles/_rules.scss +150 -0
  155. package/package.json +3 -3
  156. package/segmented/styles/_index.scss +8 -0
  157. package/select/styles/_index.scss +17 -1
  158. package/shiny-text/shiny-text.scss +1 -1
  159. package/shiny-text/styles/_index.scss +14 -105
  160. package/shiny-text/styles/_rules.scss +101 -0
  161. package/slider/styles/_index.scss +8 -0
  162. package/spotlight-card/spotlight-card.scss +1 -1
  163. package/spotlight-card/styles/_index.scss +15 -52
  164. package/spotlight-card/styles/_rules.scss +47 -0
  165. package/star-border/star-border.scss +1 -1
  166. package/star-border/styles/_index.scss +15 -125
  167. package/star-border/styles/_rules.scss +120 -0
  168. package/switch/styles/_index.scss +7 -0
  169. package/theme/styles/_dark.scss +81 -4
  170. package/theme/styles/_index.scss +1 -0
  171. package/theme/styles/_motion.scss +94 -0
  172. package/tilt-card/styles/_index.scss +15 -45
  173. package/tilt-card/styles/_rules.scss +40 -0
  174. package/tilt-card/tilt-card.scss +1 -1
  175. package/tree/styles/_index.scss +15 -1
  176. package/types/ngwr-breadcrumbs.d.ts +1 -0
  177. package/types/ngwr-cascader.d.ts +17 -1
  178. package/types/ngwr-checkbox.d.ts +51 -3
  179. package/types/ngwr-color-picker.d.ts +19 -1
  180. package/types/ngwr-file-upload.d.ts +18 -1
  181. package/types/ngwr-form.d.ts +51 -2
  182. package/types/ngwr-fuzzy-text.d.ts +5 -0
  183. package/types/ngwr-icon-adapters-feather.d.ts +11 -0
  184. package/types/ngwr-icon.d.ts +42 -1
  185. package/types/ngwr-input-otp.d.ts +23 -1
  186. package/types/ngwr-knob.d.ts +14 -0
  187. package/types/ngwr-radio.d.ts +37 -2
  188. package/types/ngwr-rating.d.ts +14 -0
  189. package/types/ngwr-segmented.d.ts +18 -1
  190. package/types/ngwr-select.d.ts +17 -1
  191. package/types/ngwr-shiny-text.d.ts +1 -0
  192. package/types/ngwr-slider.d.ts +14 -1
  193. package/types/ngwr-switch.d.ts +26 -2
  194. package/types/ngwr-textarea.d.ts +3 -0
  195. package/types/ngwr-theme.d.ts +24 -0
  196. package/types/ngwr-transfer.d.ts +17 -1
  197. package/types/ngwr-tree.d.ts +21 -1
  198. package/types/ngwr-utils.d.ts +47 -1
  199. package/types/ngwr-version.d.ts +1 -1
  200. package/typewriter/styles/_index.scss +15 -38
  201. package/typewriter/styles/_rules.scss +33 -0
  202. package/typewriter/typewriter.scss +1 -1
  203. package/virtual-scroll/styles/_index.scss +15 -32
  204. package/virtual-scroll/styles/_rules.scss +27 -0
  205. package/virtual-scroll/virtual-scroll.scss +1 -1
  206. package/waves/styles/_index.scss +15 -50
  207. package/waves/styles/_rules.scss +45 -0
  208. package/waves/waves.scss +1 -1
@@ -0,0 +1,101 @@
1
+ // Shimmering text (reactbits port). Clips an animated linear gradient to
2
+ // the text via `background-clip: text`.
3
+ //
4
+ // The keyframes are 0% → 50%, then hold at the end position. Inputs set
5
+ // `animation-duration` to (speed + delay); the keyframe hits the end at
6
+ // the 50%/totalDuration mark and rests for the rest, which collapses to
7
+ // `speed` of motion + `delay` of pause — without needing two animations.
8
+
9
+ .wr-shiny-text {
10
+ // Theme-default sweep (overridden by `[color]` / `[shineColor]`):
11
+ // gray base with a dark shine on light surfaces; dark theme restores
12
+ // the reactbits gray-with-white-flash below.
13
+ --wr-shiny-text-base: var(--wr-color-on-surface-muted, #8594a4);
14
+ --wr-shiny-text-shine: var(--wr-color-on-surface, #0f172a);
15
+
16
+ display: inline-block;
17
+ background-size: 200% auto;
18
+ background-position: 150% center;
19
+ -webkit-background-clip: text;
20
+ background-clip: text;
21
+ -webkit-text-fill-color: transparent;
22
+ animation-name: wr-shiny-text-sweep;
23
+ animation-timing-function: linear;
24
+ animation-iteration-count: infinite;
25
+ animation-direction: normal;
26
+ animation-fill-mode: both;
27
+ animation-play-state: running;
28
+
29
+ &--reverse {
30
+ animation-direction: reverse;
31
+ }
32
+
33
+ &--yoyo {
34
+ animation-direction: alternate;
35
+
36
+ &.wr-shiny-text--reverse {
37
+ animation-direction: alternate-reverse;
38
+ }
39
+ }
40
+
41
+ &--paused {
42
+ animation-play-state: paused;
43
+ }
44
+
45
+ &--pause-on-hover:hover {
46
+ animation-play-state: paused;
47
+ }
48
+ }
49
+
50
+ @keyframes wr-shiny-text-sweep {
51
+ 0% {
52
+ background-position: 150% center;
53
+ }
54
+ 50% {
55
+ background-position: -50% center;
56
+ }
57
+ 100% {
58
+ background-position: -50% center;
59
+ }
60
+ }
61
+
62
+ // Reduced motion: freeze the sweep at its rest position — the gradient's
63
+ // base color fills the text, so it stays readable with zero movement.
64
+ @media (prefers-reduced-motion: reduce) {
65
+ .wr-shiny-text {
66
+ animation: none !important;
67
+ }
68
+ }
69
+
70
+ // [wrShimmer] directive
71
+ // Same package as <wr-shiny-text>. Lightweight host-class directive —
72
+ // gradient sweep across text via `background-clip: text`.
73
+ @keyframes wr-shimmer {
74
+ 100% {
75
+ background-position-x: -200%;
76
+ }
77
+ }
78
+
79
+ .wr-shimmer {
80
+ background: linear-gradient(
81
+ 110deg,
82
+ var(--wr-color-on-surface) 30%,
83
+ rgba(var(--wr-color-primary-rgb), 0.9) 50%,
84
+ var(--wr-color-on-surface) 70%
85
+ );
86
+ background-size: 200% 100%;
87
+ background-clip: text;
88
+ -webkit-background-clip: text;
89
+ -webkit-text-fill-color: transparent;
90
+ color: transparent;
91
+ animation: wr-shimmer 2.5s linear infinite;
92
+
93
+ @media (prefers-reduced-motion: reduce) {
94
+ animation: none;
95
+ }
96
+ }
97
+
98
+ [data-theme='dark'] .wr-shiny-text {
99
+ --wr-shiny-text-base: #b5b5b5;
100
+ --wr-shiny-text-shine: #ffffff;
101
+ }
@@ -85,6 +85,14 @@
85
85
  font-variant-numeric: tabular-nums;
86
86
  }
87
87
 
88
+ // A read-only slider still takes focus and still announces its value, so it
89
+ // keeps the visual and only stops inviting the drag — `grab` on something that
90
+ // cannot move is the part that looks broken. Matches `wr-knob--readonly`.
91
+ &--readonly &__track,
92
+ &--readonly &__thumb {
93
+ cursor: default;
94
+ }
95
+
88
96
  &--disabled {
89
97
  --wr-slider-thumb-border: var(--wr-color-on-surface-muted);
90
98
  --wr-slider-fill: var(--wr-color-on-surface-muted);
@@ -1 +1 @@
1
- @forward './styles';
1
+ @forward './styles/rules';
@@ -1,52 +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
- // Cursor-tracked spotlight card (reactbits port). The `--wr-spotlight-x/y`
7
- // vars come from the host's mousemove handler; `--wr-spotlight-color` is
8
- // set inline from the `[spotlightColor]` input when provided — otherwise
9
- // the theme picks the default below. `--wr-color-on-surface-rgb` flips between
10
- // themes (dark on light surfaces, light on dark), so a single tint reads
11
- // as a dark-ish glow in light mode and a light beam in dark mode.
12
-
13
- .wr-spotlight-card {
14
- --wr-spotlight-x: 50%;
15
- --wr-spotlight-y: 50%;
16
- --wr-spotlight-color: rgba(var(--wr-color-on-surface-rgb), 0.15);
17
-
18
- position: relative;
19
- display: block;
20
- border-radius: 1.5rem;
21
- border: 1px solid var(--wr-color-outline);
22
- background-color: var(--wr-color-surface);
23
- padding: 2rem;
24
- overflow: hidden;
25
- color: var(--wr-color-on-surface);
26
-
27
- &::before {
28
- content: '';
29
- position: absolute;
30
- inset: 0;
31
- background: radial-gradient(
32
- circle at var(--wr-spotlight-x) var(--wr-spotlight-y),
33
- var(--wr-spotlight-color),
34
- transparent var(--wr-spotlight-radius, 80%)
35
- );
36
- opacity: 0;
37
- transition: opacity 0.5s ease;
38
- pointer-events: none;
39
- }
40
-
41
- &:hover::before,
42
- &:focus-within::before {
43
- opacity: 0.6;
44
- }
45
- }
46
-
47
- // Dark mode: `--wr-color-on-surface-rgb` already flips to a light value, so the
48
- // default tint above becomes a light beam on the navy surface — nudge the
49
- // alpha up a touch so it reads as bright as the classic spotlight.
50
- [data-theme='dark'] .wr-spotlight-card {
51
- --wr-spotlight-color: rgba(var(--wr-color-on-surface-rgb), 0.22);
52
- }
1
+ // Public Sass entry for `@use 'ngwr/spotlight-card'`.
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
+ // `spotlight-card.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. `spotlight-card.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,47 @@
1
+ // Cursor-tracked spotlight card (reactbits port). The `--wr-spotlight-x/y`
2
+ // vars come from the host's mousemove handler; `--wr-spotlight-color` is
3
+ // set inline from the `[spotlightColor]` input when provided — otherwise
4
+ // the theme picks the default below. `--wr-color-on-surface-rgb` flips between
5
+ // themes (dark on light surfaces, light on dark), so a single tint reads
6
+ // as a dark-ish glow in light mode and a light beam in dark mode.
7
+
8
+ .wr-spotlight-card {
9
+ --wr-spotlight-x: 50%;
10
+ --wr-spotlight-y: 50%;
11
+ --wr-spotlight-color: rgba(var(--wr-color-on-surface-rgb), 0.15);
12
+
13
+ position: relative;
14
+ display: block;
15
+ border-radius: 1.5rem;
16
+ border: 1px solid var(--wr-color-outline);
17
+ background-color: var(--wr-color-surface);
18
+ padding: 2rem;
19
+ overflow: hidden;
20
+ color: var(--wr-color-on-surface);
21
+
22
+ &::before {
23
+ content: '';
24
+ position: absolute;
25
+ inset: 0;
26
+ background: radial-gradient(
27
+ circle at var(--wr-spotlight-x) var(--wr-spotlight-y),
28
+ var(--wr-spotlight-color),
29
+ transparent var(--wr-spotlight-radius, 80%)
30
+ );
31
+ opacity: 0;
32
+ transition: opacity 0.5s ease;
33
+ pointer-events: none;
34
+ }
35
+
36
+ &:hover::before,
37
+ &:focus-within::before {
38
+ opacity: 0.6;
39
+ }
40
+ }
41
+
42
+ // Dark mode: `--wr-color-on-surface-rgb` already flips to a light value, so the
43
+ // default tint above becomes a light beam on the navy surface — nudge the
44
+ // alpha up a touch so it reads as bright as the classic spotlight.
45
+ [data-theme='dark'] .wr-spotlight-card {
46
+ --wr-spotlight-color: rgba(var(--wr-color-on-surface-rgb), 0.22);
47
+ }
@@ -1 +1 @@
1
- @forward './styles';
1
+ @forward './styles/rules';
@@ -1,125 +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
- // Star border (reactbits port). Two oversized radial-gradient "comets"
7
- // sweep along the top and bottom edges of the rounded container; the
8
- // projected content sits on a token-themed inner panel above them.
9
-
10
- .wr-star-border {
11
- // Light surfaces get a primary comet; dark theme flips to the classic
12
- // white (see block below). `[color]` overrides both inline. The light
13
- // comet gets a wider core + full opacity — a thin 10% tail washes out
14
- // to gray on white surfaces.
15
- --wr-star-border-color: var(--wr-color-primary);
16
- --wr-star-border-speed: 6s;
17
- --wr-star-border-radius: 20px;
18
- --wr-star-border-stop: 16%;
19
- --wr-star-border-opacity: 1;
20
-
21
- display: inline-block;
22
- position: relative;
23
- border: 0;
24
- background: transparent;
25
- border-radius: var(--wr-star-border-radius);
26
- overflow: hidden;
27
- cursor: inherit;
28
-
29
- &__ray {
30
- position: absolute;
31
- display: block;
32
- width: 300%;
33
- height: 50%;
34
- opacity: var(--wr-star-border-opacity);
35
- border-radius: 50%;
36
- background: radial-gradient(circle, var(--wr-star-border-color), transparent var(--wr-star-border-stop));
37
- animation: wr-star-border-bottom var(--wr-star-border-speed) linear infinite alternate;
38
- z-index: 0;
39
-
40
- &--bottom {
41
- bottom: -12px;
42
- // rtl-ok: the comet's off-screen start mark — `wr-star-border-bottom` sweeps it by `translate(-100%, 0%)`
43
- right: -250%;
44
- }
45
-
46
- &--top {
47
- top: -12px;
48
- // rtl-ok: the comet's off-screen start mark — `wr-star-border-top` sweeps it by `translate(100%, 0%)`
49
- left: -250%;
50
- animation-name: wr-star-border-top;
51
- }
52
- }
53
-
54
- // Single-ray variant — drop the top comet.
55
- &--single &__ray--top {
56
- display: none;
57
- }
58
-
59
- // Hover-only variant — rays sit hidden until the pointer is in. The
60
- // idle state must drop the animation entirely (not pause it): a paused
61
- // animation pins `opacity` at its 0% keyframe value, which beats the
62
- // cascade and leaves a frozen comet visible.
63
- &--hover &__ray {
64
- opacity: 0;
65
- animation: none;
66
- }
67
-
68
- &--hover:hover &__ray {
69
- animation: wr-star-border-bottom var(--wr-star-border-speed) linear infinite alternate;
70
- }
71
-
72
- &--hover:hover &__ray--top {
73
- animation-name: wr-star-border-top;
74
- }
75
-
76
- &__inner {
77
- position: relative;
78
- display: block;
79
- border: 1px solid var(--wr-color-outline);
80
- background: var(--wr-color-surface);
81
- color: var(--wr-color-on-surface);
82
- font-size: 1rem;
83
- text-align: center;
84
- padding: 1rem 1.625rem;
85
- border-radius: var(--wr-star-border-radius);
86
- z-index: 1;
87
- }
88
- }
89
-
90
- [data-theme='dark'] .wr-star-border {
91
- --wr-star-border-color: #ffffff;
92
- --wr-star-border-stop: 10%;
93
- --wr-star-border-opacity: 0.7;
94
- }
95
-
96
- @keyframes wr-star-border-bottom {
97
- 0% {
98
- transform: translate(0%, 0%);
99
- opacity: 1;
100
- }
101
- 100% {
102
- transform: translate(-100%, 0%);
103
- opacity: 0;
104
- }
105
- }
106
-
107
- @keyframes wr-star-border-top {
108
- 0% {
109
- transform: translate(0%, 0%);
110
- opacity: 1;
111
- }
112
- 100% {
113
- transform: translate(100%, 0%);
114
- opacity: 0;
115
- }
116
- }
117
-
118
- // Reduced motion: no sweeping comets — a frozen ray reads as a smudge,
119
- // so hide them and keep the panel border as the resting look.
120
- @media (prefers-reduced-motion: reduce) {
121
- .wr-star-border__ray {
122
- animation: none !important;
123
- opacity: 0 !important;
124
- }
125
- }
1
+ // Public Sass entry for `@use 'ngwr/star-border'`.
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
+ // `star-border.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. `star-border.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,120 @@
1
+ // Star border (reactbits port). Two oversized radial-gradient "comets"
2
+ // sweep along the top and bottom edges of the rounded container; the
3
+ // projected content sits on a token-themed inner panel above them.
4
+
5
+ .wr-star-border {
6
+ // Light surfaces get a primary comet; dark theme flips to the classic
7
+ // white (see block below). `[color]` overrides both inline. The light
8
+ // comet gets a wider core + full opacity — a thin 10% tail washes out
9
+ // to gray on white surfaces.
10
+ --wr-star-border-color: var(--wr-color-primary);
11
+ --wr-star-border-speed: 6s;
12
+ --wr-star-border-radius: 20px;
13
+ --wr-star-border-stop: 16%;
14
+ --wr-star-border-opacity: 1;
15
+
16
+ display: inline-block;
17
+ position: relative;
18
+ border: 0;
19
+ background: transparent;
20
+ border-radius: var(--wr-star-border-radius);
21
+ overflow: hidden;
22
+ cursor: inherit;
23
+
24
+ &__ray {
25
+ position: absolute;
26
+ display: block;
27
+ width: 300%;
28
+ height: 50%;
29
+ opacity: var(--wr-star-border-opacity);
30
+ border-radius: 50%;
31
+ background: radial-gradient(circle, var(--wr-star-border-color), transparent var(--wr-star-border-stop));
32
+ animation: wr-star-border-bottom var(--wr-star-border-speed) linear infinite alternate;
33
+ z-index: 0;
34
+
35
+ &--bottom {
36
+ bottom: -12px;
37
+ // rtl-ok: the comet's off-screen start mark — `wr-star-border-bottom` sweeps it by `translate(-100%, 0%)`
38
+ right: -250%;
39
+ }
40
+
41
+ &--top {
42
+ top: -12px;
43
+ // rtl-ok: the comet's off-screen start mark — `wr-star-border-top` sweeps it by `translate(100%, 0%)`
44
+ left: -250%;
45
+ animation-name: wr-star-border-top;
46
+ }
47
+ }
48
+
49
+ // Single-ray variant — drop the top comet.
50
+ &--single &__ray--top {
51
+ display: none;
52
+ }
53
+
54
+ // Hover-only variant — rays sit hidden until the pointer is in. The
55
+ // idle state must drop the animation entirely (not pause it): a paused
56
+ // animation pins `opacity` at its 0% keyframe value, which beats the
57
+ // cascade and leaves a frozen comet visible.
58
+ &--hover &__ray {
59
+ opacity: 0;
60
+ animation: none;
61
+ }
62
+
63
+ &--hover:hover &__ray {
64
+ animation: wr-star-border-bottom var(--wr-star-border-speed) linear infinite alternate;
65
+ }
66
+
67
+ &--hover:hover &__ray--top {
68
+ animation-name: wr-star-border-top;
69
+ }
70
+
71
+ &__inner {
72
+ position: relative;
73
+ display: block;
74
+ border: 1px solid var(--wr-color-outline);
75
+ background: var(--wr-color-surface);
76
+ color: var(--wr-color-on-surface);
77
+ font-size: 1rem;
78
+ text-align: center;
79
+ padding: 1rem 1.625rem;
80
+ border-radius: var(--wr-star-border-radius);
81
+ z-index: 1;
82
+ }
83
+ }
84
+
85
+ [data-theme='dark'] .wr-star-border {
86
+ --wr-star-border-color: #ffffff;
87
+ --wr-star-border-stop: 10%;
88
+ --wr-star-border-opacity: 0.7;
89
+ }
90
+
91
+ @keyframes wr-star-border-bottom {
92
+ 0% {
93
+ transform: translate(0%, 0%);
94
+ opacity: 1;
95
+ }
96
+ 100% {
97
+ transform: translate(-100%, 0%);
98
+ opacity: 0;
99
+ }
100
+ }
101
+
102
+ @keyframes wr-star-border-top {
103
+ 0% {
104
+ transform: translate(0%, 0%);
105
+ opacity: 1;
106
+ }
107
+ 100% {
108
+ transform: translate(100%, 0%);
109
+ opacity: 0;
110
+ }
111
+ }
112
+
113
+ // Reduced motion: no sweeping comets — a frozen ray reads as a smudge,
114
+ // so hide them and keep the panel border as the resting look.
115
+ @media (prefers-reduced-motion: reduce) {
116
+ .wr-star-border__ray {
117
+ animation: none !important;
118
+ opacity: 0 !important;
119
+ }
120
+ }
@@ -95,6 +95,13 @@
95
95
  }
96
96
  }
97
97
 
98
+ // A read-only switch still takes focus and still submits its value, so it
99
+ // keeps the full visual and only stops inviting the click — dimming it would
100
+ // say "disabled", which is the other state.
101
+ &--readonly &__label {
102
+ cursor: default;
103
+ }
104
+
98
105
  &--disabled {
99
106
  --wr-switch-color: var(--wr-color-on-surface-muted);
100
107
  pointer-events: none;
@@ -3,13 +3,90 @@
3
3
  @use 'colors';
4
4
  @use 'variables';
5
5
 
6
- // Dark theme overrides — opt-in via `[data-theme="dark"]` on <html>.
7
- // Drive the toggle from `WrTheme` (provided automatically with
8
- // `provideWrTheme(...)`).
6
+ // Dark theme overrides — opt-in via `[data-theme="dark"]` on <html>, or
7
+ // whatever `$theme-attribute` below is configured to. Drive the toggle from
8
+ // `WrTheme` (provided automatically with `provideWrTheme(...)`).
9
9
  //
10
10
  // Only semantic tokens flip — palette hues stay so brand-coloured
11
11
  // elements look the same regardless of theme.
12
12
 
13
+ /// The attribute the dark block keys on. Must match the `attribute` passed to
14
+ /// `provideWrTheme(...)`, and that pairing is the whole reason this variable
15
+ /// exists: `WrThemeConfig.attribute` is a RUNTIME value, and no CSS selector can
16
+ /// read one. Until v13 the selector below was the literal `[data-theme='dark']`,
17
+ /// so an app that set `provideWrTheme({ attribute: 'data-color-mode' })` got a
18
+ /// service reporting `resolved() === 'dark'`, the attribute written correctly
19
+ /// onto `<html>`, and a page that stayed light forever — no error, no warning.
20
+ ///
21
+ /// Configure the two together:
22
+ ///
23
+ /// ```scss
24
+ /// // styles.scss
25
+ /// @use 'ngwr' with ($theme-attribute: 'data-color-mode');
26
+ /// ```
27
+ /// ```ts
28
+ /// provideWrTheme({ attribute: 'data-color-mode' })
29
+ /// ```
30
+ ///
31
+ /// Only the configured attribute is emitted — the default is NOT kept as a
32
+ /// second selector. Renaming it is what decouples ngwr from another design
33
+ /// system that already owns `data-theme`, and emitting both would re-couple
34
+ /// them: that system's own `data-theme="dark"` would flip ngwr's tokens behind
35
+ /// the app's back, which is the exact collision the rename exists to avoid.
36
+ ///
37
+ /// If the two disagree the page silently stays light, so `WrTheme` publishes a
38
+ /// dev-mode check for it: the light block below writes the configured name into
39
+ /// `--wr-theme-attribute`, and the service warns when what it reads there is not
40
+ /// what it was configured with. A stylesheet that is missing or predates v13
41
+ /// leaves the property empty and the check stays quiet — it can only fire on a
42
+ /// real disagreement.
43
+ $theme-attribute: 'data-theme' !default;
44
+
45
+ /// The dark-theme selector, for a stylesheet that has to build its own.
46
+ ///
47
+ /// @example scss
48
+ /// #{dark.dark-selector()} .my-thing { ... }
49
+ @function dark-selector() {
50
+ @return '[#{$theme-attribute}=\'dark\']';
51
+ }
52
+
53
+ /// Wrap a declaration block so it only applies in dark mode, honouring
54
+ /// `$theme-attribute`. Prefer this over writing `[data-theme='dark']` by hand —
55
+ /// a hand-written literal is exactly what BUG-3 was.
56
+ ///
57
+ /// @example scss
58
+ /// @use 'ngwr/theme' as theme;
59
+ ///
60
+ /// .my-card {
61
+ /// background: #fff;
62
+ ///
63
+ /// @include theme.dark {
64
+ /// background: #0b1120;
65
+ /// }
66
+ /// }
67
+ @mixin dark() {
68
+ @if & {
69
+ @at-root #{dark-selector()} #{&} {
70
+ @content;
71
+ }
72
+ } @else {
73
+ #{dark-selector()} {
74
+ @content;
75
+ }
76
+ }
77
+ }
78
+
79
+ :root {
80
+ // The attribute this compiled stylesheet keys its dark block on, published so
81
+ // `WrTheme` can compare it against `WrThemeConfig.attribute` in dev mode and
82
+ // say so when the two were configured apart. Read with
83
+ // `getPropertyValue('--wr-theme-attribute')`, never with `var()`.
84
+ //
85
+ // unused-ok: read by `WrTheme` through the CSSOM rather than painted with —
86
+ // it carries a name, not a value, so no declaration can reference it.
87
+ --wr-theme-attribute: #{$theme-attribute};
88
+ }
89
+
13
90
  // Intents re-tuned for the dark canvas. Looped (below) so each gets the
14
91
  // FULL symmetric shade set — the hand blocks used to ship only base+rgb,
15
92
  // leaving -light/-dark/-lighter/-darker baked from the LIGHT palette.
@@ -37,7 +114,7 @@ $_light: #262f44;
37
114
  $_medium: #6d7682;
38
115
  $_dark: #e6ebf3;
39
116
 
40
- [data-theme='dark'] {
117
+ #{dark-selector()} {
41
118
  // Canvas (was `--wr-color-white` in light mode)
42
119
  // Deeper than slate-900 so an elevated surface in slate-800 reads
43
120
  // as a real layer rather than vanishing into the background.
@@ -4,3 +4,4 @@
4
4
  @forward 'dark';
5
5
  @forward 'focus';
6
6
  @forward 'mixins';
7
+ @forward 'motion';