@filip.mazev/blocks 1.4.11 → 1.4.12

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.
@@ -0,0 +1,49 @@
1
+ @mixin choice-well {
2
+ background-image: linear-gradient(
3
+ 180deg,
4
+ color-mix(in srgb, var(--bx-border-strong) 24%, var(--bx-glass-surface)),
5
+ var(--bx-glass-surface) 55%,
6
+ color-mix(in srgb, var(--bx-border-strong) 10%, var(--bx-glass-surface))
7
+ ) !important;
8
+ border-top-color: var(--bx-border-strong);
9
+ border-bottom-color: var(--bx-border-default);
10
+ }
11
+
12
+ @mixin choice-accent-face {
13
+ background-image: linear-gradient(
14
+ 180deg,
15
+ color-mix(in srgb, var(--bx-color-accent-50) 24%, var(--bx-accent)),
16
+ var(--bx-accent) 42%,
17
+ var(--bx-accent) 65%,
18
+ color-mix(in srgb, var(--bx-border-accent) 18%, var(--bx-accent))
19
+ ) !important;
20
+ border-top-color: color-mix(in srgb, var(--bx-color-accent-100) 60%, var(--bx-accent));
21
+ border-inline-color: var(--bx-accent);
22
+ border-bottom-color: var(--bx-border-accent);
23
+ }
24
+
25
+ @mixin choice-thumb {
26
+ background-image: radial-gradient(
27
+ circle at 32% 22%,
28
+ var(--bx-color-accent-50),
29
+ var(--bx-color-accent-100) 38%,
30
+ var(--bx-color-accent-300) 80%,
31
+ var(--bx-color-accent-400)
32
+ ) !important;
33
+ border-top-color: var(--bx-color-accent-50);
34
+ border-inline-color: var(--bx-color-accent-200);
35
+ border-bottom-color: var(--bx-color-accent-500);
36
+ }
37
+
38
+ @mixin choice-flat-accessibility {
39
+ :host-context(.high-contrast) &,
40
+ :host-context(.bx-high-contrast-scope) & {
41
+ background-image: none !important;
42
+ border-color: var(--bx-glass-edge);
43
+ }
44
+
45
+ @media (forced-colors: active) {
46
+ background-image: none !important;
47
+ border-color: ButtonText;
48
+ }
49
+ }
@@ -4,3 +4,4 @@
4
4
  @forward 'palettes';
5
5
  @forward 'motion';
6
6
  @forward 'field-state';
7
+ @forward 'choice-finish';
@@ -9,7 +9,7 @@
9
9
  border-radius: radius(pill);
10
10
  background: linear-gradient(
11
11
  to right,
12
- var(--bx-primary) 0 var(--bx-slider-progress, 50%),
12
+ var(--bx-accent) 0 var(--bx-slider-progress, 50%),
13
13
  var(--bx-bg-neutral) var(--bx-slider-progress, 50%) 100%
14
14
  );
15
15
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 16%);
@@ -28,7 +28,7 @@
28
28
  var(--bx-bg-surface);
29
29
  border-color: color-mix(
30
30
  in srgb,
31
- var(--bx-slider-light-color, var(--bx-primary))
31
+ var(--bx-slider-light-color, var(--bx-accent))
32
32
  calc(var(--bx-slider-light-strength, 0.18) * 100%),
33
33
  var(--bx-border-strong)
34
34
  );
@@ -36,7 +36,7 @@
36
36
  box-shadow:
37
37
  inset 0 1px 1px rgb(255 255 255 / 45%),
38
38
  inset 0 -1px 2px
39
- color-mix(in srgb, var(--bx-slider-light-color, var(--bx-primary)) 30%, transparent),
39
+ color-mix(in srgb, var(--bx-slider-light-color, var(--bx-accent)) 30%, transparent),
40
40
  0 2px 5px rgb(0 0 0 / 18%);
41
41
  }
42
42
 
@@ -90,7 +90,7 @@
90
90
  padding: 1px;
91
91
  background: radial-gradient(
92
92
  circle at var(--bx-slider-light-x, 35%) var(--bx-slider-light-y, 0%),
93
- var(--bx-slider-light-color, var(--bx-primary)),
93
+ var(--bx-slider-light-color, var(--bx-accent)),
94
94
  transparent 75%
95
95
  );
96
96
  opacity: var(--bx-slider-light-strength, 0.25);
@@ -135,7 +135,7 @@ input.bx-slider {
135
135
  }
136
136
 
137
137
  &:focus-visible {
138
- outline: 2px solid var(--bx-border-brand);
138
+ outline: 2px solid var(--bx-border-accent);
139
139
  outline-offset: 3px;
140
140
  border-radius: radius(pill);
141
141
  }
@@ -83,7 +83,7 @@ $required-theme-keys: (
83
83
  }
84
84
 
85
85
  @each $key, $value in $theme {
86
- @if string.index($key, 'meta-') !=1 {
86
+ @if string.index($key, 'meta-') != 1 {
87
87
  @if not list.index($required-theme-keys, $key) {
88
88
  @error "Strict Theme Error: '#{$theme-name}' contains an invalid key '#{$key}'. Remove or rename it.";
89
89
  }
@@ -102,22 +102,20 @@ $required-theme-keys: (
102
102
  'blue': 0.0722,
103
103
  );
104
104
 
105
- @each $channel, $weight in $weights {
106
- $part: math.div(color.channel($value, $channel, $space: rgb), 255);
105
+ @each $channel, $weight in $weights {
106
+ $part: math.div(color.channel($value, $channel, $space: rgb), 255);
107
107
 
108
- /* stylelint-disable-next-line number-max-precision -- Preserve the exact sRGB linearization threshold. */
109
- @if $part <=0.04045 {
110
- $part: math.div($part, 12.92);
111
- }
108
+ /* stylelint-disable-next-line number-max-precision -- Preserve the exact sRGB linearization threshold. */
109
+ @if $part <= 0.04045 {
110
+ $part: math.div($part, 12.92);
111
+ } @else {
112
+ $part: math.pow(math.div($part + 0.055, 1.055), 2.4);
113
+ }
112
114
 
113
- @else {
114
- $part: math.pow(math.div($part + 0.055, 1.055), 2.4);
115
+ $result: $result + $part * $weight;
115
116
  }
116
117
 
117
- $result: $result + $part * $weight;
118
- }
119
-
120
- @return $result;
118
+ @return $result;
121
119
  }
122
120
 
123
121
  @function _contrast($first, $second) {
@@ -134,7 +132,7 @@ $required-theme-keys: (
134
132
  $dark: #000000;
135
133
  }
136
134
 
137
- @if _contrast($dark, $background)>=_contrast(#ffffff, $background) {
135
+ @if _contrast($dark, $background) >= _contrast(#ffffff, $background) {
138
136
  @return $dark;
139
137
  }
140
138
 
@@ -163,12 +161,13 @@ $required-theme-keys: (
163
161
  $text-key: 'text-accent';
164
162
  $border-key: 'border-accent';
165
163
 
166
- @if $role =='primary' {
164
+ @if $role == 'primary' {
167
165
  $text-key: 'text-brand';
168
166
  $border-key: 'border-brand';
169
167
  }
170
168
 
171
- @return ($role: $base,
169
+ @return (
170
+ $role: $base,
172
171
  '#{$role}-hover': $hover,
173
172
  '#{$role}-active': $active,
174
173
  '#{$role}-subtle': $subtle,
@@ -176,38 +175,21 @@ $required-theme-keys: (
176
175
  'on-#{$role}-hover': _on-color($hover),
177
176
  'on-#{$role}-active': _on-color($active),
178
177
  $text-key: $text,
179
- $border-key: get-color-from-palette($palette, _mode($dark, 800, 300)));
178
+ $border-key: get-color-from-palette($palette, _mode($dark, 800, 300))
179
+ );
180
180
  }
181
181
 
182
182
  @function _make-theme($brand, $accent, $dark, $overrides) {
183
183
  $base: (
184
- 'bg-canvas': color.mix(get-color-from-palette($brand, _mode($dark, 50, 900)),
185
- _mode($brand, #ffffff, #000000),
186
- 2%),
187
- 'bg-surface': color.mix(get-color-from-palette($brand, _mode($dark, 50, 900)),
188
- get-color-from-palette('neutral', _mode($dark, 50, 1000)),
189
- 2%),
190
- 'bg-surface-alt': color.mix(get-color-from-palette($brand, _mode($dark, 50, 900)),
191
- get-color-from-palette('neutral', _mode($dark, 50, 900)),
192
- 2%),
193
- 'bg-element': color.mix(get-color-from-palette($brand, _mode($dark, 100, 900)),
194
- get-color-from-palette('neutral', _mode($dark, 100, 800)),
195
- 2%),
196
- 'bg-element-hover': color.mix(get-color-from-palette($brand, _mode($dark, 100, 900)),
197
- get-color-from-palette('neutral', _mode($dark, 200, 700)),
198
- 2%),
199
- 'bg-element-active': color.mix(get-color-from-palette($brand, _mode($dark, 100, 900)),
200
- get-color-from-palette('neutral', _mode($dark, 300, 600)),
201
- 2%),
202
- 'bg-neutral': color.mix(get-color-from-palette($brand, _mode($dark, 50, 900)),
203
- get-color-from-palette('neutral', _mode($dark, 100, 900)),
204
- 2%),
205
- 'bg-neutral-hover': color.mix(get-color-from-palette($brand, _mode($dark, 50, 900)),
206
- get-color-from-palette('neutral', _mode($dark, 50, 800)),
207
- 2%),
208
- 'bg-neutral-active': color.mix(get-color-from-palette($brand, _mode($dark, 50, 900)),
209
- get-color-from-palette('neutral', _mode($dark, 200, 600)),
210
- 2%),
184
+ 'bg-canvas': _mode($dark, #ffffff, #000000),
185
+ 'bg-surface': get-color-from-palette('neutral', _mode($dark, 50, 1000)),
186
+ 'bg-surface-alt': get-color-from-palette('neutral', _mode($dark, 50, 900)),
187
+ 'bg-element': get-color-from-palette('neutral', _mode($dark, 100, 800)),
188
+ 'bg-element-hover': get-color-from-palette('neutral', _mode($dark, 200, 700)),
189
+ 'bg-element-active': get-color-from-palette('neutral', _mode($dark, 300, 600)),
190
+ 'bg-neutral': get-color-from-palette('neutral', _mode($dark, 100, 900)),
191
+ 'bg-neutral-hover': get-color-from-palette('neutral', _mode($dark, 50, 800)),
192
+ 'bg-neutral-active': get-color-from-palette('neutral', _mode($dark, 200, 600)),
211
193
  'text-heading': _mode($dark, get-color-from-palette('neutral', 900), #ffffff),
212
194
  'text-primary': get-color-from-palette('neutral', _mode($dark, 700, 200)),
213
195
  'text-secondary': get-color-from-palette('neutral', _mode($dark, 600, 400)),
@@ -222,23 +204,28 @@ $required-theme-keys: (
222
204
  'meta-accent-palette': $accent,
223
205
  );
224
206
 
225
- @each $status,
226
- $palette in ('info': 'information', 'success': 'success', 'warn': 'warn', 'danger': 'danger') {
227
- $base: map.merge($base,
228
- ('text-#{$status}': get-color-from-palette($palette, _mode($dark, 700, 400)),
207
+ @each $status,
208
+ $palette
209
+ in ('info': 'information', 'success': 'success', 'warn': 'warn', 'danger': 'danger')
210
+ {
211
+ $base: map.merge(
212
+ $base,
213
+ (
214
+ 'text-#{$status}': get-color-from-palette($palette, _mode($dark, 700, 400)),
229
215
  'border-#{$status}': get-color-from-palette($palette, 400),
230
216
  'bg-#{$status}': get-color-from-palette($palette, _mode($dark, 100, 900)),
231
217
  'bg-#{$status}-hover': get-color-from-palette($palette, _mode($dark, 200, 800)),
232
218
  'bg-#{$status}-active': get-color-from-palette($palette, _mode($dark, 300, 700)),
233
219
  'bg-#{$status}-disabled': get-color-from-palette($palette, _mode($dark, 50, 1000)),
234
220
  'bg-#{$status}-subtle': get-color-from-palette($palette, _mode($dark, 50, 1000)),
235
- ));
236
- }
221
+ )
222
+ );
223
+ }
237
224
 
238
- $base: map.merge($base, _color-roles($brand, 'primary', $dark));
239
- $base: map.merge($base, _color-roles($accent, 'accent', $dark));
225
+ $base: map.merge($base, _color-roles($brand, 'primary', $dark));
226
+ $base: map.merge($base, _color-roles($accent, 'accent', $dark));
240
227
 
241
- @return validate-theme(map.merge($base, $overrides), '#{$brand}-#{$accent}');
228
+ @return validate-theme(map.merge($base, $overrides), '#{$brand}-#{$accent}');
242
229
  }
243
230
 
244
231
  /* stylelint-enable scss/at-function-pattern */
@@ -257,7 +244,7 @@ $base: map.merge($base, _color-roles($accent, 'accent', $dark));
257
244
  --bx-glass-accent: var(--bx-primary);
258
245
 
259
246
  @each $key, $value in $config {
260
- @if string.index($key, 'meta-') !=1 {
247
+ @if string.index($key, 'meta-') != 1 {
261
248
  --bx-#{$key}: #{$value};
262
249
  }
263
250
  }
@@ -270,28 +257,22 @@ $base: map.merge($base, _color-roles($accent, 'accent', $dark));
270
257
  }
271
258
 
272
259
  @each $key in $required-theme-keys {
273
- @if string.index($key, 'bg-')==1 {
260
+ @if string.index($key, 'bg-') == 1 {
274
261
  .bx-#{$key} {
275
262
  background-color: var(--bx-#{$key});
276
263
  transition: background-color 0.2s ease-in-out;
277
264
  }
278
- }
279
-
280
- @else if string.index($key, 'text-')==1 {
265
+ } @else if string.index($key, 'text-') == 1 {
281
266
  .bx-#{$key} {
282
267
  color: var(--bx-#{$key});
283
268
  transition: color 0.2s ease-in-out;
284
269
  }
285
- }
286
-
287
- @else if string.index($key, 'border-')==1 {
270
+ } @else if string.index($key, 'border-') == 1 {
288
271
  .bx-#{$key} {
289
272
  border-color: var(--bx-#{$key});
290
273
  transition: border-color 0.2s ease-in-out;
291
274
  }
292
- }
293
-
294
- @else if not string.index($key, 'scroll-') and string.index($key, 'meta-') !=1 {
275
+ } @else if not string.index($key, 'scroll-') and string.index($key, 'meta-') != 1 {
295
276
  .bx-bg-#{$key} {
296
277
  background-color: var(--bx-#{$key});
297
278
  transition: background-color 0.2s ease-in-out;
@@ -307,4 +288,4 @@ $base: map.merge($base, _color-roles($accent, 'accent', $dark));
307
288
  transition: border-color 0.2s ease-in-out;
308
289
  }
309
290
  }
310
- }
291
+ }
@@ -12,6 +12,10 @@
12
12
  box-shadow: var(--bx-glass-shadow, 0 2px 6px rgb(0 0 0 / .08));
13
13
  color: var(--bx-glass-text, var(--bx-text-primary, CanvasText));
14
14
  border-color: var(--bx-glass-edge, var(--bx-border-subtle, GrayText));
15
+ }
16
+
17
+ /* Buttons use the same curve before their runtime surface mounts. */
18
+ [data-bx-surface], .bx-btn {
15
19
  --bx-glass-material-blur: calc(4px + 24px * var(--bx-glassiness, .5) * var(--bx-glassiness, .5));
16
20
  --bx-glass-material-opacity: calc(.06 + 1.02 * var(--bx-glassiness, .5) - .28 * var(--bx-glassiness, .5) * var(--bx-glassiness, .5));
17
21
  }
@@ -91,7 +91,7 @@ This is a bounded, stylized lighting model. The browser's backdrop filter still
91
91
 
92
92
  ## Overlay fades
93
93
 
94
- Overlays fade in over 180 ms and out over 140 ms. Their dimensions, clipping and text size remain unchanged. The fade composites the material surface itself, keeping its configured blur and tint throughout. The surrounding positioning pane stays opaque so it does not create a backdrop root that cuts off the page behind the glass. Reversing an active fade continues from its current opacity; the interrupted promise resolves to `cancelled`.
94
+ Overlays fade in over 180 ms and out over 140 ms using the Web Animations API. Their dimensions, clipping and text size remain unchanged. The fade composites the material surface itself, keeping its configured blur and tint throughout. The surrounding positioning pane stays opaque so it does not create a backdrop root that cuts off the page behind the glass. Native opacity interpolation avoids per-frame style mutations and lighting invalidation. Reversing an active fade continues from its current opacity; the interrupted promise resolves to `cancelled`.
95
95
 
96
96
  The transition temporarily owns the first material surface’s `opacity` and the target’s `visibility`. If no material is present, it fades the target. The overlay positioner retains all geometry and transforms. Supply an already positioned target and destroy the transition when its overlay is removed. Both endpoints must belong to the same document. `refresh()` remains a compatibility no-op because a fade requires no geometry measurements. Version 0.1’s `createLiquidTransition` and associated type names remain deprecated aliases for `createGlassTransition`.
97
97
 
@@ -19,10 +19,6 @@ function rememberAttributes(element, attributes) {
19
19
  function finiteClamp(value, low, high, fallback) {
20
20
  return value === void 0 || !Number.isFinite(value) ? fallback : Math.min(high, Math.max(low, value));
21
21
  }
22
- function smoothstep(low, high, value) {
23
- const t = Math.min(1, Math.max(0, (value - low) / (high - low)));
24
- return t * t * (3 - 2 * t);
25
- }
26
22
  const configurationEvent = "bx-glass-config-change";
27
23
  const attributes = [
28
24
  "data-bx-glass-quality",
@@ -1823,29 +1819,28 @@ function createGlassTransition(origin, target, options = {}) {
1823
1819
  if (!view) throw new Error("Glass transitions must be mounted in a browser document.");
1824
1820
  if (origin.ownerDocument !== doc) throw new Error("Glass transition endpoints must share a document.");
1825
1821
  const skin = target.matches("[data-bx-surface]") ? target : target.querySelector("[data-bx-surface]") ?? target;
1826
- const restoreOpacity = rememberStyles(skin, ["opacity"]);
1827
1822
  const restoreVisibility = rememberStyles(target, ["visibility"]);
1828
1823
  const opacity = Number(view.getComputedStyle(skin).opacity);
1824
+ const readOpacity = () => Number(view.getComputedStyle(skin).opacity);
1829
1825
  const preference = view.matchMedia("(prefers-reduced-motion: reduce)");
1830
1826
  let disposed = false;
1831
1827
  let active = false;
1832
- let value = 0, from = 0, destination = 0, elapsed = 0;
1828
+ let value = 0;
1829
+ let destination = 0;
1830
+ let animation;
1833
1831
  let unsubscribe;
1834
1832
  let resolvePending;
1835
1833
  const reduced = () => {
1836
1834
  const inherited = inheritedAttribute(origin, "data-bx-reduced-motion");
1837
1835
  return options.reducedMotion ?? (inherited === null ? preference.matches : inherited === "true");
1838
1836
  };
1839
- const paint = () => {
1840
- skin.style.opacity = String(value * opacity);
1841
- options.onUpdate?.();
1842
- };
1843
1837
  function settle() {
1844
1838
  active = false;
1845
1839
  value = destination;
1846
1840
  unsubscribe?.();
1847
1841
  unsubscribe = void 0;
1848
- restoreOpacity();
1842
+ animation?.cancel();
1843
+ animation = void 0;
1849
1844
  restoreVisibility();
1850
1845
  if (destination === 0) target.style.visibility = "hidden";
1851
1846
  const resolve = resolvePending;
@@ -1854,12 +1849,13 @@ function createGlassTransition(origin, target, options = {}) {
1854
1849
  }
1855
1850
  function move(open) {
1856
1851
  if (disposed) return Promise.resolve("cancelled");
1852
+ const from = animation && opacity > 0 ? readOpacity() / opacity : value;
1857
1853
  resolvePending?.("cancelled");
1854
+ animation?.cancel();
1855
+ animation = void 0;
1858
1856
  unsubscribe?.();
1859
1857
  unsubscribe = void 0;
1860
- from = value;
1861
1858
  destination = open ? 1 : 0;
1862
- elapsed = 0;
1863
1859
  active = true;
1864
1860
  restoreVisibility();
1865
1861
  const finished = new Promise((resolve) => {
@@ -1867,18 +1863,18 @@ function createGlassTransition(origin, target, options = {}) {
1867
1863
  });
1868
1864
  if (reduced() || from === destination) settle();
1869
1865
  else {
1870
- paint();
1871
- const duration = (open ? .18 : .14) * Math.abs(destination - from);
1872
- unsubscribe = subscribeFrame((dt) => {
1873
- elapsed += dt;
1874
- value = from + (destination - from) * smoothstep(0, duration, elapsed);
1875
- paint();
1876
- if (disposed) return false;
1877
- if (elapsed >= duration) {
1878
- settle();
1879
- return false;
1880
- }
1881
- return true;
1866
+ const current = skin.animate([{ opacity: from * opacity }, { opacity: destination * opacity }], {
1867
+ duration: (open ? 180 : 140) * Math.abs(destination - from),
1868
+ easing: "ease-in-out",
1869
+ fill: "both"
1870
+ });
1871
+ animation = current;
1872
+ current.finished.then(() => {
1873
+ if (animation === current && !disposed) settle();
1874
+ }).catch(() => {});
1875
+ if (options.onUpdate) unsubscribe = subscribeFrame(() => {
1876
+ options.onUpdate?.();
1877
+ return active && !disposed;
1882
1878
  });
1883
1879
  }
1884
1880
  return finished;
@@ -1902,7 +1898,8 @@ function createGlassTransition(origin, target, options = {}) {
1902
1898
  resolvePending = void 0;
1903
1899
  preference.removeEventListener("change", onPreference);
1904
1900
  doc.removeEventListener(configurationEvent, onPreference);
1905
- restoreOpacity();
1901
+ animation?.cancel();
1902
+ animation = void 0;
1906
1903
  restoreVisibility();
1907
1904
  }
1908
1905
  };