vireglass 3.0.0 → 3.1.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.
- package/README.md +30 -0
- package/dist/dom.cjs +199 -16
- package/dist/dom.cjs.map +1 -1
- package/dist/dom.d.cts +24 -2
- package/dist/dom.d.ts +24 -2
- package/dist/dom.js +198 -17
- package/dist/dom.js.map +1 -1
- package/package.json +2 -1
- package/src/dom/index.ts +175 -13
- package/src/dom/interim.ts +47 -0
- package/src/dom/rim.ts +6 -4
- package/src/dom/stats.ts +28 -0
package/dist/dom.d.cts
CHANGED
|
@@ -134,7 +134,7 @@ declare const RIM_WIDTH_PX: 1;
|
|
|
134
134
|
* everything around it. It has to hold at every angle, including the one facing away from the key
|
|
135
135
|
* light where the ordinary rim falls back to a dim dark line.
|
|
136
136
|
*/
|
|
137
|
-
declare function contrastRimCss(bodyLuma: number, rimLuma: number): string;
|
|
137
|
+
declare function contrastRimCss(bodyLuma: number, rimLuma: number, appear?: number): string;
|
|
138
138
|
|
|
139
139
|
declare function shadowAlphaFrom(sample: {
|
|
140
140
|
busy: number;
|
|
@@ -309,6 +309,20 @@ declare function cached<T>(key: string, build: () => T): T;
|
|
|
309
309
|
declare function clearMapCache(): void;
|
|
310
310
|
declare function mapCacheSize(): number;
|
|
311
311
|
|
|
312
|
+
type RenderStats = {
|
|
313
|
+
/** `elementsFromPoint` backdrop probes. */
|
|
314
|
+
probes: number;
|
|
315
|
+
/** Displacement maps baked at full device resolution (cache hits are not bakes). */
|
|
316
|
+
fullBakes: number;
|
|
317
|
+
/** Displacement maps baked at reduced resolution: interim morphs and the finger path. */
|
|
318
|
+
reducedBakes: number;
|
|
319
|
+
/** Filter elements put into the shared `<defs>`, replacing or adding. */
|
|
320
|
+
filterSwaps: number;
|
|
321
|
+
};
|
|
322
|
+
/** The work the renderer has done since the last reset; the hook for a consumer's performance gate. */
|
|
323
|
+
declare function renderStats(): RenderStats;
|
|
324
|
+
declare function resetRenderStats(): void;
|
|
325
|
+
|
|
312
326
|
type AttachGlassOptions = {
|
|
313
327
|
material?: Partial<VireGlassMaterial>;
|
|
314
328
|
/** Defaults to the element's measured box (size + `border-radius`). */
|
|
@@ -405,6 +419,14 @@ type GlassHandle = {
|
|
|
405
419
|
strength: number;
|
|
406
420
|
} | null): void;
|
|
407
421
|
setMorph(morph: GlassMorph | null): void;
|
|
422
|
+
/**
|
|
423
|
+
* While on, the element is changing shape every frame (a morph, a drag, a growth). It stops
|
|
424
|
+
* probing the backdrop, stops rebuilding its maps and keeps its filter: the existing map is
|
|
425
|
+
* stretched over the live box. A change of `setMorph` shapes still updates the map, at reduced
|
|
426
|
+
* resolution and only once the new image has decoded. Turning it off does one full-resolution
|
|
427
|
+
* rebuild and one probe. Repeated calls with the same value do nothing.
|
|
428
|
+
*/
|
|
429
|
+
setInterim(on: boolean): void;
|
|
408
430
|
/**
|
|
409
431
|
* Replaces the backdrop the glass adapts to, without re-attaching, and repaints. The same
|
|
410
432
|
* object as `sample` in the options; `null` goes back to probing declared backgrounds.
|
|
@@ -414,4 +436,4 @@ type GlassHandle = {
|
|
|
414
436
|
};
|
|
415
437
|
declare function attachGlass(el: HTMLElement, opts?: AttachGlassOptions): GlassHandle;
|
|
416
438
|
|
|
417
|
-
export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
|
|
439
|
+
export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RenderStats, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
|
package/dist/dom.d.ts
CHANGED
|
@@ -134,7 +134,7 @@ declare const RIM_WIDTH_PX: 1;
|
|
|
134
134
|
* everything around it. It has to hold at every angle, including the one facing away from the key
|
|
135
135
|
* light where the ordinary rim falls back to a dim dark line.
|
|
136
136
|
*/
|
|
137
|
-
declare function contrastRimCss(bodyLuma: number, rimLuma: number): string;
|
|
137
|
+
declare function contrastRimCss(bodyLuma: number, rimLuma: number, appear?: number): string;
|
|
138
138
|
|
|
139
139
|
declare function shadowAlphaFrom(sample: {
|
|
140
140
|
busy: number;
|
|
@@ -309,6 +309,20 @@ declare function cached<T>(key: string, build: () => T): T;
|
|
|
309
309
|
declare function clearMapCache(): void;
|
|
310
310
|
declare function mapCacheSize(): number;
|
|
311
311
|
|
|
312
|
+
type RenderStats = {
|
|
313
|
+
/** `elementsFromPoint` backdrop probes. */
|
|
314
|
+
probes: number;
|
|
315
|
+
/** Displacement maps baked at full device resolution (cache hits are not bakes). */
|
|
316
|
+
fullBakes: number;
|
|
317
|
+
/** Displacement maps baked at reduced resolution: interim morphs and the finger path. */
|
|
318
|
+
reducedBakes: number;
|
|
319
|
+
/** Filter elements put into the shared `<defs>`, replacing or adding. */
|
|
320
|
+
filterSwaps: number;
|
|
321
|
+
};
|
|
322
|
+
/** The work the renderer has done since the last reset; the hook for a consumer's performance gate. */
|
|
323
|
+
declare function renderStats(): RenderStats;
|
|
324
|
+
declare function resetRenderStats(): void;
|
|
325
|
+
|
|
312
326
|
type AttachGlassOptions = {
|
|
313
327
|
material?: Partial<VireGlassMaterial>;
|
|
314
328
|
/** Defaults to the element's measured box (size + `border-radius`). */
|
|
@@ -405,6 +419,14 @@ type GlassHandle = {
|
|
|
405
419
|
strength: number;
|
|
406
420
|
} | null): void;
|
|
407
421
|
setMorph(morph: GlassMorph | null): void;
|
|
422
|
+
/**
|
|
423
|
+
* While on, the element is changing shape every frame (a morph, a drag, a growth). It stops
|
|
424
|
+
* probing the backdrop, stops rebuilding its maps and keeps its filter: the existing map is
|
|
425
|
+
* stretched over the live box. A change of `setMorph` shapes still updates the map, at reduced
|
|
426
|
+
* resolution and only once the new image has decoded. Turning it off does one full-resolution
|
|
427
|
+
* rebuild and one probe. Repeated calls with the same value do nothing.
|
|
428
|
+
*/
|
|
429
|
+
setInterim(on: boolean): void;
|
|
408
430
|
/**
|
|
409
431
|
* Replaces the backdrop the glass adapts to, without re-attaching, and repaints. The same
|
|
410
432
|
* object as `sample` in the options; `null` goes back to probing declared backgrounds.
|
|
@@ -414,4 +436,4 @@ type GlassHandle = {
|
|
|
414
436
|
};
|
|
415
437
|
declare function attachGlass(el: HTMLElement, opts?: AttachGlassOptions): GlassHandle;
|
|
416
438
|
|
|
417
|
-
export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
|
|
439
|
+
export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RenderStats, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
|
package/dist/dom.js
CHANGED
|
@@ -340,6 +340,55 @@ function probeBackdrop(el, opts = {}) {
|
|
|
340
340
|
return statsFromSamples(samples);
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
// src/dom/stats.ts
|
|
344
|
+
var counts = { probes: 0, fullBakes: 0, reducedBakes: 0, filterSwaps: 0 };
|
|
345
|
+
function renderStats() {
|
|
346
|
+
return { ...counts };
|
|
347
|
+
}
|
|
348
|
+
function resetRenderStats() {
|
|
349
|
+
counts.probes = 0;
|
|
350
|
+
counts.fullBakes = 0;
|
|
351
|
+
counts.reducedBakes = 0;
|
|
352
|
+
counts.filterSwaps = 0;
|
|
353
|
+
}
|
|
354
|
+
function bump(key) {
|
|
355
|
+
counts[key] += 1;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// src/dom/interim.ts
|
|
359
|
+
function quantise(value, step = 2) {
|
|
360
|
+
return Math.round(value / step) * step;
|
|
361
|
+
}
|
|
362
|
+
function interimKey(width, height, cornerRadius, morph, extra) {
|
|
363
|
+
return `i|${quantise(width)}x${quantise(height)}r${quantise(cornerRadius)}|${morph}|${extra}`;
|
|
364
|
+
}
|
|
365
|
+
function filterSignature(blur, ior, iorSpread, hasHue) {
|
|
366
|
+
return `${blur}|${ior}|${iorSpread > 1e-4 ? iorSpread : 0}|${hasHue ? "h" : "-"}`;
|
|
367
|
+
}
|
|
368
|
+
function createLru(limit) {
|
|
369
|
+
const store2 = /* @__PURE__ */ new Map();
|
|
370
|
+
return {
|
|
371
|
+
get(key) {
|
|
372
|
+
const hit = store2.get(key);
|
|
373
|
+
if (hit === void 0) return void 0;
|
|
374
|
+
store2.delete(key);
|
|
375
|
+
store2.set(key, hit);
|
|
376
|
+
return hit;
|
|
377
|
+
},
|
|
378
|
+
set(key, value) {
|
|
379
|
+
store2.delete(key);
|
|
380
|
+
store2.set(key, value);
|
|
381
|
+
if (store2.size > limit) {
|
|
382
|
+
const oldest = store2.keys().next();
|
|
383
|
+
if (!oldest.done) store2.delete(oldest.value);
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
get size() {
|
|
387
|
+
return store2.size;
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
343
392
|
// src/dom/support.ts
|
|
344
393
|
var backdropFilterSupport = null;
|
|
345
394
|
var svgBackdropFilterSupport = null;
|
|
@@ -557,9 +606,11 @@ function rimGradientCss(optics, ambient, light, appear = 1) {
|
|
|
557
606
|
return `conic-gradient(from ${start.toFixed(1)}deg, ${line.join(", ")}), conic-gradient(${dark} 0deg, ${dark} 360deg)`;
|
|
558
607
|
}
|
|
559
608
|
var RIM_WIDTH_PX = RIM.widthPx;
|
|
560
|
-
function contrastRimCss(bodyLuma, rimLuma) {
|
|
609
|
+
function contrastRimCss(bodyLuma, rimLuma, appear = 1) {
|
|
561
610
|
const v = to2552(rimLuma);
|
|
562
|
-
|
|
611
|
+
const present = clamp012(appear);
|
|
612
|
+
const colour = present >= 1 ? `rgb(${v},${v},${v})` : `rgba(${v},${v},${v},${present.toFixed(3)})`;
|
|
613
|
+
return `conic-gradient(${colour} 0deg, ${colour} 360deg)`;
|
|
563
614
|
}
|
|
564
615
|
|
|
565
616
|
// src/dom/nesting.ts
|
|
@@ -677,7 +728,7 @@ function createGlassGroup(members, opts = {}) {
|
|
|
677
728
|
}
|
|
678
729
|
function update() {
|
|
679
730
|
if (destroyed) return;
|
|
680
|
-
const
|
|
731
|
+
const probe2 = opts.probe ?? probeBackdrop;
|
|
681
732
|
members.forEach(({ el, legibility }, index) => {
|
|
682
733
|
const rect = el.getBoundingClientRect();
|
|
683
734
|
if (rect.width <= 0 || rect.height <= 0) {
|
|
@@ -688,7 +739,7 @@ function createGlassGroup(members, opts = {}) {
|
|
|
688
739
|
String(index),
|
|
689
740
|
rect.left + rect.width / 2,
|
|
690
741
|
rect.top + rect.height / 2,
|
|
691
|
-
|
|
742
|
+
probe2(el),
|
|
692
743
|
legibility ?? 0
|
|
693
744
|
);
|
|
694
745
|
});
|
|
@@ -852,6 +903,18 @@ function fallbackFilterCss(optics) {
|
|
|
852
903
|
const saturate = 1 + optics.colorPickup;
|
|
853
904
|
return `blur(${blurPx}px) saturate(${saturate})`;
|
|
854
905
|
}
|
|
906
|
+
function probe(el) {
|
|
907
|
+
bump("probes");
|
|
908
|
+
return probeBackdrop(el);
|
|
909
|
+
}
|
|
910
|
+
function decoded(url) {
|
|
911
|
+
if (typeof Image === "undefined") return Promise.resolve();
|
|
912
|
+
const img = new Image();
|
|
913
|
+
img.src = url;
|
|
914
|
+
return typeof img.decode === "function" ? img.decode().catch(() => void 0) : Promise.resolve();
|
|
915
|
+
}
|
|
916
|
+
var INTERIM_IDLE_MS = 2e3;
|
|
917
|
+
var isEmpty = (g) => quantise(g.width) < 1 || quantise(g.height) < 1;
|
|
855
918
|
var to2553 = (v) => Math.round(Math.min(Math.max(v, 0), 1) * 255);
|
|
856
919
|
function rgbCss(r, g, b) {
|
|
857
920
|
return `rgb(${to2553(r)} ${to2553(g)} ${to2553(b)})`;
|
|
@@ -878,6 +941,13 @@ function attachGlass(el, opts = {}) {
|
|
|
878
941
|
let filterEl = null;
|
|
879
942
|
let destroyed = false;
|
|
880
943
|
let mapKey = "";
|
|
944
|
+
let interim = false;
|
|
945
|
+
let settling = false;
|
|
946
|
+
let lastSample = null;
|
|
947
|
+
let seq = 0;
|
|
948
|
+
let shownSeq = 0;
|
|
949
|
+
let idleTimer = null;
|
|
950
|
+
const interimMaps = createLru(8);
|
|
881
951
|
let morph = null;
|
|
882
952
|
const onlyWhenTouched = opts.variant === "interactive";
|
|
883
953
|
let appear = onlyWhenTouched ? 0 : opts.appear ?? 1;
|
|
@@ -889,6 +959,7 @@ function attachGlass(el, opts = {}) {
|
|
|
889
959
|
mapKey = "";
|
|
890
960
|
deform.setElastic(elasticAllowed(opts.accessibility ?? a11y));
|
|
891
961
|
apply();
|
|
962
|
+
if (interim) requestInterimMap();
|
|
892
963
|
});
|
|
893
964
|
warnIfNested(el);
|
|
894
965
|
const host = hostFor(el);
|
|
@@ -914,24 +985,111 @@ function attachGlass(el, opts = {}) {
|
|
|
914
985
|
const part = (s) => s ? `${s.offsetX},${s.offsetY},${s.width},${s.height},${s.cornerRadius}` : "-";
|
|
915
986
|
return `${morph.smoothing}/${part(morph.shape)}/${part(morph.shape2)}`;
|
|
916
987
|
}
|
|
988
|
+
function invalidate() {
|
|
989
|
+
seq += 1;
|
|
990
|
+
shownSeq = seq;
|
|
991
|
+
}
|
|
992
|
+
function keepInterim() {
|
|
993
|
+
if (idleTimer !== null) clearTimeout(idleTimer);
|
|
994
|
+
idleTimer = setTimeout(leaveInterim, INTERIM_IDLE_MS);
|
|
995
|
+
}
|
|
996
|
+
function leaveInterim() {
|
|
997
|
+
if (idleTimer !== null) clearTimeout(idleTimer);
|
|
998
|
+
idleTimer = null;
|
|
999
|
+
if (destroyed || !interim) return;
|
|
1000
|
+
interim = false;
|
|
1001
|
+
invalidate();
|
|
1002
|
+
mapKey = "";
|
|
1003
|
+
settling = true;
|
|
1004
|
+
apply();
|
|
1005
|
+
}
|
|
1006
|
+
function retarget(f, map, hue) {
|
|
1007
|
+
const images = f.querySelectorAll("feImage");
|
|
1008
|
+
images[0]?.setAttribute("href", map.url);
|
|
1009
|
+
if (hue) images[1]?.setAttribute("href", hue.url);
|
|
1010
|
+
for (const pass of f.querySelectorAll("feDisplacementMap")) {
|
|
1011
|
+
const ratio = Number(pass.getAttribute("data-vireglass-ratio") ?? 1);
|
|
1012
|
+
pass.setAttribute("scale", String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
function requestInterimMap() {
|
|
1016
|
+
if (!svgSupported || !filterEl || destroyed) return;
|
|
1017
|
+
const geometry = opts.geometry ?? measureGeometry(el);
|
|
1018
|
+
if (isEmpty(geometry)) return;
|
|
1019
|
+
const opticsNow = optics();
|
|
1020
|
+
const key = interimKey(
|
|
1021
|
+
geometry.width,
|
|
1022
|
+
geometry.height,
|
|
1023
|
+
geometry.cornerRadius,
|
|
1024
|
+
JSON.stringify([morph?.smoothing, morph?.shape, morph?.shape2, morph?.shapes]),
|
|
1025
|
+
`a${appear.toFixed(3)}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}`
|
|
1026
|
+
);
|
|
1027
|
+
let rec = interimMaps.get(key);
|
|
1028
|
+
if (!rec) {
|
|
1029
|
+
bump("reducedBakes");
|
|
1030
|
+
rec = { map: buildDisplacementMap(opticsNow, geometry, Math.min(1, devicePixelRatio()), morphState()), ready: false };
|
|
1031
|
+
interimMaps.set(key, rec);
|
|
1032
|
+
}
|
|
1033
|
+
const mine = seq += 1;
|
|
1034
|
+
const record = rec;
|
|
1035
|
+
const forFilter = filterEl;
|
|
1036
|
+
const show = () => {
|
|
1037
|
+
if (destroyed || filterEl !== forFilter || mine <= shownSeq) return;
|
|
1038
|
+
shownSeq = mine;
|
|
1039
|
+
retarget(forFilter, record.map, null);
|
|
1040
|
+
};
|
|
1041
|
+
if (record.ready) {
|
|
1042
|
+
show();
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
void decoded(record.map.url).then(() => {
|
|
1046
|
+
record.ready = true;
|
|
1047
|
+
show();
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
917
1050
|
function apply() {
|
|
918
1051
|
if (destroyed) return;
|
|
1052
|
+
if (interim) keepInterim();
|
|
919
1053
|
const geometry = opts.geometry ?? measureGeometry(el);
|
|
920
1054
|
const opticsNow = optics();
|
|
921
|
-
const sample = supplied ??
|
|
1055
|
+
const sample = supplied ?? (interim && lastSample ? lastSample : probe(el));
|
|
1056
|
+
lastSample = sample;
|
|
922
1057
|
const light = shouldInkBeLight(sample, wasLight);
|
|
923
1058
|
wasLight = light;
|
|
924
1059
|
const body = opts.body === false ? null : bodyCss(settledOptics(), sample, light ? 1 : 0, accent, appear);
|
|
925
1060
|
if (svgSupported) {
|
|
926
1061
|
const key = `a${appear.toFixed(3)}|m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}:${opticsNow.blur}`;
|
|
927
|
-
if (key !== mapKey || !filterEl) {
|
|
928
|
-
const map = cached(`d|${key}`, () =>
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1062
|
+
if (interim && filterEl) ; else if (isEmpty(geometry)) ; else if (key !== mapKey || !filterEl) {
|
|
1063
|
+
const map = cached(`d|${key}`, () => {
|
|
1064
|
+
bump("fullBakes");
|
|
1065
|
+
return buildDisplacementMap(opticsNow, geometry, devicePixelRatio(), morphState());
|
|
1066
|
+
});
|
|
1067
|
+
const hue = hasSpectralEdge(opticsNow) ? cached(`h|${key}`, () => {
|
|
1068
|
+
bump("fullBakes");
|
|
1069
|
+
return buildSpectralMap(opticsNow, geometry, devicePixelRatio());
|
|
1070
|
+
}) : null;
|
|
1071
|
+
const signature = filterSignature(opticsNow.blur, opticsNow.ior, opticsNow.iorSpread, !!hue);
|
|
1072
|
+
if (settling && filterEl?.getAttribute("data-vireglass-signature") === signature) {
|
|
1073
|
+
settling = false;
|
|
1074
|
+
const mine = seq += 1;
|
|
1075
|
+
const forFilter = filterEl;
|
|
1076
|
+
const forKey = key;
|
|
1077
|
+
void Promise.all([decoded(map.url), hue ? decoded(hue.url) : void 0]).then(() => {
|
|
1078
|
+
if (destroyed || filterEl !== forFilter || mapKey !== forKey || mine <= shownSeq) return;
|
|
1079
|
+
shownSeq = mine;
|
|
1080
|
+
retarget(forFilter, map, hue);
|
|
1081
|
+
});
|
|
1082
|
+
} else {
|
|
1083
|
+
settling = false;
|
|
1084
|
+
invalidate();
|
|
1085
|
+
const defs = getFilterHost(host).querySelector("defs");
|
|
1086
|
+
const next = buildFilterElement(id, map.url, opticsNow, map.scale, hue);
|
|
1087
|
+
next.setAttribute("data-vireglass-signature", signature);
|
|
1088
|
+
if (filterEl?.parentNode) defs.replaceChild(next, filterEl);
|
|
1089
|
+
else defs.appendChild(next);
|
|
1090
|
+
bump("filterSwaps");
|
|
1091
|
+
filterEl = next;
|
|
1092
|
+
}
|
|
935
1093
|
mapKey = key;
|
|
936
1094
|
}
|
|
937
1095
|
el.style.setProperty("backdrop-filter", `url(#${id})`);
|
|
@@ -955,7 +1113,7 @@ function attachGlass(el, opts = {}) {
|
|
|
955
1113
|
const pole = withPresence(resolveBody(opticsNow, sample, light ? 1 : 0), opticsNow).tintLuma;
|
|
956
1114
|
el.style.setProperty(
|
|
957
1115
|
"--vireglass-rim",
|
|
958
|
-
(opts.accessibility ?? a11y).increaseContrast ? contrastRimCss(pole, contrastRimLuma(pole)) : rimGradientCss(opticsNow, [tr, tg, tb], opts.light ?? REST_LIGHT, appear)
|
|
1116
|
+
(opts.accessibility ?? a11y).increaseContrast ? contrastRimCss(pole, contrastRimLuma(pole), appear) : rimGradientCss(opticsNow, [tr, tg, tb], opts.light ?? REST_LIGHT, appear)
|
|
959
1117
|
);
|
|
960
1118
|
el.style.setProperty("--vireglass-rim-width", `${RIM_WIDTH_PX}px`);
|
|
961
1119
|
el.style.setProperty("--vireglass-radius", `${geometry.cornerRadius}px`);
|
|
@@ -978,7 +1136,9 @@ function attachGlass(el, opts = {}) {
|
|
|
978
1136
|
const base = optics();
|
|
979
1137
|
const rise = raiseIntoGlass(sampleOut.press);
|
|
980
1138
|
const risen = optics({ ...opts.material, roughness: (opts.material?.roughness ?? VIREGLASS_MATERIAL.roughness) * rise.solid });
|
|
981
|
-
|
|
1139
|
+
if (interim) keepInterim();
|
|
1140
|
+
bump("reducedBakes");
|
|
1141
|
+
const map = buildDisplacementMap(risen, geometry, 1, {
|
|
982
1142
|
...morphState(),
|
|
983
1143
|
touch: {
|
|
984
1144
|
x: sampleOut.touchX,
|
|
@@ -991,6 +1151,7 @@ function attachGlass(el, opts = {}) {
|
|
|
991
1151
|
wavePhase: sampleOut.wavePhase
|
|
992
1152
|
}
|
|
993
1153
|
});
|
|
1154
|
+
invalidate();
|
|
994
1155
|
if (filterEl) {
|
|
995
1156
|
const feImage = filterEl.querySelector("feImage");
|
|
996
1157
|
feImage?.setAttribute("href", map.url);
|
|
@@ -1013,7 +1174,7 @@ function attachGlass(el, opts = {}) {
|
|
|
1013
1174
|
el.style.setProperty("--vireglass-glow-opacity", "0");
|
|
1014
1175
|
return;
|
|
1015
1176
|
}
|
|
1016
|
-
const [gr, gg, gb] = ambientFrom(supplied ??
|
|
1177
|
+
const [gr, gg, gb] = ambientFrom(supplied ?? (interim && lastSample ? lastSample : probe(el)));
|
|
1017
1178
|
const cx = (x + geometry.width / 2) / geometry.width * 100;
|
|
1018
1179
|
const cy = (y + geometry.height / 2) / geometry.height * 100;
|
|
1019
1180
|
const reach = halfMinDp(geometry) * TOUCH_RADIUS_FRACTION;
|
|
@@ -1037,7 +1198,9 @@ function attachGlass(el, opts = {}) {
|
|
|
1037
1198
|
lastFrameAt = 0;
|
|
1038
1199
|
el.style.setProperty("--vireglass-glow-opacity", "0");
|
|
1039
1200
|
opts.onGlow?.(null);
|
|
1201
|
+
settling = !interim;
|
|
1040
1202
|
apply();
|
|
1203
|
+
if (interim) requestInterimMap();
|
|
1041
1204
|
return;
|
|
1042
1205
|
}
|
|
1043
1206
|
frame = requestAnimationFrame(tick);
|
|
@@ -1085,6 +1248,9 @@ function attachGlass(el, opts = {}) {
|
|
|
1085
1248
|
}
|
|
1086
1249
|
function destroy() {
|
|
1087
1250
|
destroyed = true;
|
|
1251
|
+
invalidate();
|
|
1252
|
+
if (idleTimer !== null) clearTimeout(idleTimer);
|
|
1253
|
+
idleTimer = null;
|
|
1088
1254
|
stopWatchingA11y();
|
|
1089
1255
|
if (attached.get(el) === handle) attached.delete(el);
|
|
1090
1256
|
if (frame !== null) cancelAnimationFrame(frame);
|
|
@@ -1126,6 +1292,7 @@ function attachGlass(el, opts = {}) {
|
|
|
1126
1292
|
if (next === appear) return;
|
|
1127
1293
|
appear = next;
|
|
1128
1294
|
apply();
|
|
1295
|
+
if (interim) requestInterimMap();
|
|
1129
1296
|
},
|
|
1130
1297
|
setAccent(next) {
|
|
1131
1298
|
accent = next ?? void 0;
|
|
@@ -1148,9 +1315,23 @@ function attachGlass(el, opts = {}) {
|
|
|
1148
1315
|
},
|
|
1149
1316
|
setMorph(next) {
|
|
1150
1317
|
morph = next && next.smoothing > 0 ? next : null;
|
|
1318
|
+
if (interim) {
|
|
1319
|
+
apply();
|
|
1320
|
+
requestInterimMap();
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1151
1323
|
mapKey = "";
|
|
1152
1324
|
apply();
|
|
1153
1325
|
},
|
|
1326
|
+
setInterim(on) {
|
|
1327
|
+
if (destroyed || on === interim) return;
|
|
1328
|
+
if (on) {
|
|
1329
|
+
interim = true;
|
|
1330
|
+
keepInterim();
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
leaveInterim();
|
|
1334
|
+
},
|
|
1154
1335
|
setSample(next) {
|
|
1155
1336
|
supplied = next ?? void 0;
|
|
1156
1337
|
apply();
|
|
@@ -1161,6 +1342,6 @@ function attachGlass(el, opts = {}) {
|
|
|
1161
1342
|
return handle;
|
|
1162
1343
|
}
|
|
1163
1344
|
|
|
1164
|
-
export { RIM_WIDTH_PX, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
|
|
1345
|
+
export { RIM_WIDTH_PX, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
|
|
1165
1346
|
//# sourceMappingURL=dom.js.map
|
|
1166
1347
|
//# sourceMappingURL=dom.js.map
|