@surdeddd/bottom-sheet 0.24.0 → 0.24.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.
- package/README.md +2 -2
- package/README.ru.md +2 -2
- package/dist/webgl.cjs +123 -48
- package/dist/webgl.d.cts +2 -1
- package/dist/webgl.d.ts +2 -1
- package/dist/webgl.js +123 -48
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ HTML.
|
|
|
9
9
|
[](https://www.npmjs.com/package/@surdeddd/bottom-sheet)
|
|
10
10
|
[](https://www.npmjs.com/package/@surdeddd/bottom-sheet)
|
|
11
11
|

|
|
12
|
-

|
|
13
13
|

|
|
14
14
|

|
|
15
15
|
|
|
@@ -623,7 +623,7 @@ const sheet = new BottomSheetCore({
|
|
|
623
623
|
| `/react` `/vue` `/svelte` `/solid` `/qwik` | 27 to 33 KB | The full engine plus the adapter |
|
|
624
624
|
| `/element` | 33.3 KB | The full engine, the element and its styles |
|
|
625
625
|
| `/overlay` | 8.4 KB | The standalone [overlay](docs/overlay.md) |
|
|
626
|
-
| `/webgl` |
|
|
626
|
+
| `/webgl` | 6.4 KB | Optional [GPU renderer](docs/webgl.md) for the sheet surface |
|
|
627
627
|
| `/debug` | 0.9 KB | `attachDebugOverlay(engine)`: a live panel of the engine's state |
|
|
628
628
|
|
|
629
629
|
An option whose feature is missing warns once in development and is ignored.
|
package/README.ru.md
CHANGED
|
@@ -9,7 +9,7 @@ Solid, Qwik, Preact** и под **веб-компонентом** `<bottom-sheet
|
|
|
9
9
|
[](https://www.npmjs.com/package/@surdeddd/bottom-sheet)
|
|
10
10
|
[](https://www.npmjs.com/package/@surdeddd/bottom-sheet)
|
|
11
11
|

|
|
12
|
-

|
|
13
13
|

|
|
14
14
|

|
|
15
15
|
|
|
@@ -637,7 +637,7 @@ const sheet = new BottomSheetCore({
|
|
|
637
637
|
| `/react` `/vue` `/svelte` `/solid` `/qwik` | от 27 до 33 KB | Полный движок вместе с адаптером |
|
|
638
638
|
| `/element` | 33.3 KB | Полный движок, элемент и его стили |
|
|
639
639
|
| `/overlay` | 8.4 KB | Отдельный [оверлей](docs/overlay.md) |
|
|
640
|
-
| `/webgl` |
|
|
640
|
+
| `/webgl` | 6.4 KB | Необязательный [рендерер на GPU](docs/webgl.md) для поверхности шторки |
|
|
641
641
|
| `/debug` | 0.9 KB | `attachDebugOverlay(engine)`: панель с состоянием движка в реальном времени |
|
|
642
642
|
|
|
643
643
|
Опция, для которой не подключена возможность, один раз предупреждает в
|
package/dist/webgl.cjs
CHANGED
|
@@ -9,6 +9,22 @@ var supportsHighpFragment = (gl) => {
|
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
+
var SOFTWARE = /swiftshader|llvmpipe|softpipe|software|basic render/i;
|
|
13
|
+
var MASKED = /^webkit webgl$/i;
|
|
14
|
+
var rendererName = (gl) => {
|
|
15
|
+
const plain = String(gl.getParameter(gl.RENDERER) ?? "");
|
|
16
|
+
if (plain && !MASKED.test(plain)) return plain;
|
|
17
|
+
const info = gl.getExtension("WEBGL_debug_renderer_info");
|
|
18
|
+
if (!info) return "";
|
|
19
|
+
return String(gl.getParameter(info.UNMASKED_RENDERER_WEBGL) ?? "");
|
|
20
|
+
};
|
|
21
|
+
var drawsOnCpu = (gl) => {
|
|
22
|
+
try {
|
|
23
|
+
return SOFTWARE.test(rendererName(gl));
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
12
28
|
var hasWebGL = () => {
|
|
13
29
|
if (typeof document === "undefined") return false;
|
|
14
30
|
if (typeof WebGLRenderingContext === "undefined" && typeof WebGL2RenderingContext === "undefined") {
|
|
@@ -34,14 +50,16 @@ var createGLHandle = (onLost) => {
|
|
|
34
50
|
canvas.style.position = "fixed";
|
|
35
51
|
canvas.style.left = "0";
|
|
36
52
|
canvas.style.top = "0";
|
|
53
|
+
canvas.style.width = "100%";
|
|
54
|
+
canvas.style.height = "100%";
|
|
37
55
|
canvas.style.pointerEvents = "none";
|
|
38
56
|
const attrs = {
|
|
39
57
|
alpha: true,
|
|
40
58
|
premultipliedAlpha: true,
|
|
41
|
-
antialias:
|
|
59
|
+
antialias: false,
|
|
42
60
|
depth: false,
|
|
43
61
|
stencil: false,
|
|
44
|
-
preserveDrawingBuffer:
|
|
62
|
+
preserveDrawingBuffer: true
|
|
45
63
|
};
|
|
46
64
|
let gl = null;
|
|
47
65
|
let isWebGL2 = false;
|
|
@@ -85,8 +103,6 @@ var resizeDrawingBuffer = (handle, cssWidth, cssHeight, dpr) => {
|
|
|
85
103
|
handle.canvas.width = w;
|
|
86
104
|
handle.canvas.height = h;
|
|
87
105
|
}
|
|
88
|
-
handle.canvas.style.width = `${cssWidth}px`;
|
|
89
|
-
handle.canvas.style.height = `${cssHeight}px`;
|
|
90
106
|
handle.gl.viewport(0, 0, w, h);
|
|
91
107
|
};
|
|
92
108
|
|
|
@@ -102,7 +118,7 @@ precision ${precision} float;
|
|
|
102
118
|
|
|
103
119
|
uniform vec2 u_resolution;
|
|
104
120
|
uniform vec4 u_rect;
|
|
105
|
-
uniform
|
|
121
|
+
uniform vec4 u_radius;
|
|
106
122
|
uniform vec4 u_color;
|
|
107
123
|
uniform float u_shadow;
|
|
108
124
|
uniform float u_bend;
|
|
@@ -115,7 +131,9 @@ uniform sampler2D u_scroll;
|
|
|
115
131
|
uniform vec4 u_scrollRect;
|
|
116
132
|
uniform vec2 u_scrollMap;
|
|
117
133
|
|
|
118
|
-
float roundedBoxSDF(vec2 p, vec2 halfSize,
|
|
134
|
+
float roundedBoxSDF(vec2 p, vec2 halfSize, vec4 radii) {
|
|
135
|
+
vec2 side = p.x < 0.0 ? radii.xw : radii.yz;
|
|
136
|
+
float r = min(p.y < 0.0 ? side.x : side.y, min(halfSize.x, halfSize.y));
|
|
119
137
|
vec2 q = abs(p) - halfSize + r;
|
|
120
138
|
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
|
121
139
|
}
|
|
@@ -131,8 +149,7 @@ void main() {
|
|
|
131
149
|
vec2 p = frag - center;
|
|
132
150
|
p.y -= bend;
|
|
133
151
|
|
|
134
|
-
float
|
|
135
|
-
float d = roundedBoxSDF(p, halfSize, r);
|
|
152
|
+
float d = roundedBoxSDF(p, halfSize, u_radius);
|
|
136
153
|
float surface = 1.0 - smoothstep(-1.0, 1.0, d);
|
|
137
154
|
|
|
138
155
|
vec2 uv = (p + halfSize) / u_rect.zw;
|
|
@@ -256,7 +273,14 @@ var createSurfaceProgram = (gl, highp = true) => {
|
|
|
256
273
|
frame.width * dpr,
|
|
257
274
|
frame.height * dpr
|
|
258
275
|
);
|
|
259
|
-
|
|
276
|
+
const [topLeft, topRight, bottomRight, bottomLeft] = frame.radii;
|
|
277
|
+
gl.uniform4f(
|
|
278
|
+
uRadius,
|
|
279
|
+
topLeft * dpr,
|
|
280
|
+
topRight * dpr,
|
|
281
|
+
bottomRight * dpr,
|
|
282
|
+
bottomLeft * dpr
|
|
283
|
+
);
|
|
260
284
|
gl.uniform4f(uColor, ...frame.color);
|
|
261
285
|
gl.uniform1f(uShadow, frame.shadow);
|
|
262
286
|
gl.uniform1f(uBend, state.bend * dpr);
|
|
@@ -616,6 +640,7 @@ var parseColor = (value) => {
|
|
|
616
640
|
}
|
|
617
641
|
return readColor(value);
|
|
618
642
|
};
|
|
643
|
+
var parentAcrossShadow = (node) => node.parentElement ?? node.getRootNode().host ?? null;
|
|
619
644
|
var parseRadius = (value) => {
|
|
620
645
|
const n = parseFloat(value);
|
|
621
646
|
return Number.isFinite(n) ? n : 0;
|
|
@@ -661,7 +686,12 @@ var webglRenderer = (options = {}) => ({
|
|
|
661
686
|
const cs = getComputedStyle(element);
|
|
662
687
|
return {
|
|
663
688
|
color: parseColor(cs.backgroundColor),
|
|
664
|
-
|
|
689
|
+
radii: [
|
|
690
|
+
parseRadius(cs.borderTopLeftRadius),
|
|
691
|
+
parseRadius(cs.borderTopRightRadius),
|
|
692
|
+
parseRadius(cs.borderBottomRightRadius),
|
|
693
|
+
parseRadius(cs.borderBottomLeftRadius)
|
|
694
|
+
]
|
|
665
695
|
};
|
|
666
696
|
};
|
|
667
697
|
let surfaceStyle = readSurfaceStyle();
|
|
@@ -696,6 +726,12 @@ var webglRenderer = (options = {}) => ({
|
|
|
696
726
|
bail("no-webgl");
|
|
697
727
|
return;
|
|
698
728
|
}
|
|
729
|
+
if (!options.allowSoftware && drawsOnCpu(handle.gl)) {
|
|
730
|
+
handle.destroy();
|
|
731
|
+
handle = null;
|
|
732
|
+
bail("software-renderer");
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
699
735
|
program = createSurfaceProgram(handle.gl, handle.highp);
|
|
700
736
|
if (!program) {
|
|
701
737
|
handle.destroy();
|
|
@@ -706,30 +742,22 @@ var webglRenderer = (options = {}) => ({
|
|
|
706
742
|
const parent = element.parentElement ?? document.body;
|
|
707
743
|
parent.insertBefore(handle.canvas, element);
|
|
708
744
|
let canvasZ = "";
|
|
745
|
+
let canvasPosition = "fixed";
|
|
709
746
|
const followStack = () => {
|
|
710
747
|
if (!handle) return;
|
|
711
|
-
const
|
|
712
|
-
const
|
|
748
|
+
const cs = getComputedStyle(element);
|
|
749
|
+
const position = cs.position === "absolute" ? "absolute" : "fixed";
|
|
750
|
+
if (position !== canvasPosition) {
|
|
751
|
+
canvasPosition = position;
|
|
752
|
+
handle.canvas.style.position = position;
|
|
753
|
+
}
|
|
754
|
+
const next = cs.zIndex && cs.zIndex !== "auto" ? String(Number(cs.zIndex) - 1) : "0";
|
|
713
755
|
if (next === canvasZ) return;
|
|
714
756
|
canvasZ = next;
|
|
715
757
|
handle.canvas.style.zIndex = next;
|
|
716
758
|
};
|
|
717
759
|
followStack();
|
|
718
760
|
suppressDomPaint();
|
|
719
|
-
const readFrame = () => {
|
|
720
|
-
if (!handle) return null;
|
|
721
|
-
const rect = element.getBoundingClientRect();
|
|
722
|
-
if (rect.width <= 0 || rect.height <= 0) return null;
|
|
723
|
-
return {
|
|
724
|
-
x: rect.left,
|
|
725
|
-
y: rect.top,
|
|
726
|
-
width: rect.width,
|
|
727
|
-
height: rect.height,
|
|
728
|
-
radius: surfaceStyle.radius,
|
|
729
|
-
color: surfaceStyle.color,
|
|
730
|
-
shadow: shadowStrength
|
|
731
|
-
};
|
|
732
|
-
};
|
|
733
761
|
const dprOf = () => options.dpr ?? window.devicePixelRatio ?? 1;
|
|
734
762
|
const releaseCapture = () => {
|
|
735
763
|
releaseText?.();
|
|
@@ -753,41 +781,52 @@ var webglRenderer = (options = {}) => ({
|
|
|
753
781
|
capture = next;
|
|
754
782
|
releaseText = hideCapturedText(next.hiddenNodes);
|
|
755
783
|
};
|
|
756
|
-
const scrollLayer = (
|
|
784
|
+
const scrollLayer = (sheet) => {
|
|
757
785
|
const scroll = capture?.scroll;
|
|
758
786
|
const scroller = ctx.scrollContainer;
|
|
759
787
|
if (!scroll || !scroller) return null;
|
|
760
788
|
const box = scroller.getBoundingClientRect();
|
|
761
|
-
const left = box.left + scroller.clientLeft -
|
|
762
|
-
const top = box.top + scroller.clientTop -
|
|
789
|
+
const left = box.left + scroller.clientLeft - sheet.left;
|
|
790
|
+
const top = box.top + scroller.clientTop - sheet.top;
|
|
763
791
|
return {
|
|
764
792
|
texture: scroll.texture,
|
|
765
793
|
rect: [
|
|
766
|
-
left /
|
|
767
|
-
top /
|
|
768
|
-
(left + scroller.clientWidth) /
|
|
769
|
-
(top + scroller.clientHeight) /
|
|
794
|
+
left / sheet.width,
|
|
795
|
+
top / sheet.height,
|
|
796
|
+
(left + scroller.clientWidth) / sheet.width,
|
|
797
|
+
(top + scroller.clientHeight) / sheet.height
|
|
770
798
|
],
|
|
771
799
|
map: [
|
|
772
|
-
|
|
800
|
+
sheet.height / scroll.height,
|
|
773
801
|
(scroll.above + scroller.scrollTop - scroll.top) / scroll.height
|
|
774
802
|
]
|
|
775
803
|
};
|
|
776
804
|
};
|
|
777
805
|
const paint = () => {
|
|
778
806
|
if (disposed || !handle || !program) return;
|
|
779
|
-
const
|
|
780
|
-
|
|
807
|
+
const sheet = element.getBoundingClientRect();
|
|
808
|
+
const area = handle.canvas.getBoundingClientRect();
|
|
809
|
+
if (sheet.width <= 0 || sheet.height <= 0) return;
|
|
810
|
+
if (area.width <= 0 || area.height <= 0) return;
|
|
781
811
|
const dpr = dprOf();
|
|
782
|
-
resizeDrawingBuffer(handle,
|
|
812
|
+
resizeDrawingBuffer(handle, area.width, area.height, dpr);
|
|
783
813
|
const motion = Math.min(1, Math.abs(bend) / MAX_BEND_PX);
|
|
814
|
+
const frame = {
|
|
815
|
+
x: sheet.left - area.left,
|
|
816
|
+
y: sheet.top - area.top,
|
|
817
|
+
width: sheet.width,
|
|
818
|
+
height: sheet.height,
|
|
819
|
+
radii: surfaceStyle.radii,
|
|
820
|
+
color: surfaceStyle.color,
|
|
821
|
+
shadow: shadowStrength
|
|
822
|
+
};
|
|
784
823
|
program.draw(frame, {
|
|
785
824
|
bend,
|
|
786
825
|
dpr,
|
|
787
826
|
sheen: sheenStrength,
|
|
788
827
|
glass: glassStrength * motion,
|
|
789
828
|
content: capture?.texture ?? null,
|
|
790
|
-
scroll: scrollLayer(
|
|
829
|
+
scroll: scrollLayer(sheet)
|
|
791
830
|
});
|
|
792
831
|
};
|
|
793
832
|
const tick = () => {
|
|
@@ -806,6 +845,7 @@ var webglRenderer = (options = {}) => ({
|
|
|
806
845
|
paint();
|
|
807
846
|
running = false;
|
|
808
847
|
frameId = null;
|
|
848
|
+
queueRefresh();
|
|
809
849
|
return;
|
|
810
850
|
}
|
|
811
851
|
frameId = requestAnimationFrame(tick);
|
|
@@ -844,36 +884,71 @@ var webglRenderer = (options = {}) => ({
|
|
|
844
884
|
subtree: true,
|
|
845
885
|
characterData: true
|
|
846
886
|
});
|
|
847
|
-
const
|
|
887
|
+
const onGeometry = () => {
|
|
848
888
|
followStack();
|
|
849
889
|
if (!ctx.isDragging()) paint();
|
|
850
890
|
wake();
|
|
851
|
-
}
|
|
891
|
+
};
|
|
892
|
+
const geometryObserver = new MutationObserver(onGeometry);
|
|
852
893
|
geometryObserver.observe(element, {
|
|
853
894
|
attributes: true,
|
|
854
895
|
attributeFilter: ["style"]
|
|
855
896
|
});
|
|
856
897
|
const refreshSurfaceStyle = () => {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
898
|
+
const moved = geometryObserver.takeRecords().length > 0;
|
|
899
|
+
const style = element.style;
|
|
900
|
+
const transition = style.transition;
|
|
901
|
+
style.transition = "none";
|
|
902
|
+
restoreDom();
|
|
903
|
+
const next = readSurfaceStyle();
|
|
904
|
+
suppressDomPaint();
|
|
905
|
+
void getComputedStyle(element).backgroundColor;
|
|
906
|
+
style.transition = transition;
|
|
907
|
+
geometryObserver.takeRecords();
|
|
908
|
+
const changed = next.radii.some((radius, i) => radius !== surfaceStyle.radii[i]) || next.color.some((channel, i) => channel !== surfaceStyle.color[i]);
|
|
909
|
+
surfaceStyle = next;
|
|
910
|
+
if (!moved) {
|
|
911
|
+
followStack();
|
|
912
|
+
return changed;
|
|
913
|
+
}
|
|
914
|
+
onGeometry();
|
|
915
|
+
return false;
|
|
916
|
+
};
|
|
917
|
+
let refreshQueued = false;
|
|
918
|
+
const queueRefresh = () => {
|
|
919
|
+
if (disposed || refreshQueued) return;
|
|
920
|
+
refreshQueued = true;
|
|
921
|
+
requestAnimationFrame(() => {
|
|
922
|
+
refreshQueued = false;
|
|
923
|
+
if (!disposed && refreshSurfaceStyle()) paint();
|
|
924
|
+
});
|
|
863
925
|
};
|
|
926
|
+
const onThemeSignal = () => {
|
|
927
|
+
if (!ctx.isDragging() && !ctx.isAnimating()) queueRefresh();
|
|
928
|
+
};
|
|
929
|
+
const themeObserver = new MutationObserver(onThemeSignal);
|
|
930
|
+
themeObserver.observe(element, {
|
|
931
|
+
attributes: true,
|
|
932
|
+
attributeFilter: ["class"]
|
|
933
|
+
});
|
|
934
|
+
for (let node = parentAcrossShadow(element); node; node = parentAcrossShadow(node)) {
|
|
935
|
+
themeObserver.observe(node, { attributes: true });
|
|
936
|
+
}
|
|
937
|
+
const scheme = typeof matchMedia === "function" ? matchMedia("(prefers-color-scheme: dark)") : null;
|
|
938
|
+
scheme?.addEventListener?.("change", onThemeSignal);
|
|
864
939
|
const onResize = () => {
|
|
865
940
|
if (disposed) return;
|
|
866
941
|
refreshSurfaceStyle();
|
|
867
942
|
paint();
|
|
868
943
|
};
|
|
869
944
|
window.addEventListener("resize", onResize, { passive: true });
|
|
870
|
-
window.addEventListener("scroll", onResize, { passive: true });
|
|
871
945
|
paint();
|
|
872
946
|
return () => {
|
|
873
947
|
contentObserver.disconnect();
|
|
874
948
|
geometryObserver.disconnect();
|
|
949
|
+
themeObserver.disconnect();
|
|
950
|
+
scheme?.removeEventListener?.("change", onThemeSignal);
|
|
875
951
|
window.removeEventListener("resize", onResize);
|
|
876
|
-
window.removeEventListener("scroll", onResize);
|
|
877
952
|
teardown();
|
|
878
953
|
};
|
|
879
954
|
}
|
package/dist/webgl.d.cts
CHANGED
|
@@ -7,9 +7,10 @@ type WebGLRendererOptions = {
|
|
|
7
7
|
glass?: number;
|
|
8
8
|
liftContent?: boolean;
|
|
9
9
|
dpr?: number;
|
|
10
|
+
allowSoftware?: boolean;
|
|
10
11
|
onUnsupported?: (reason: WebGLUnsupportedReason) => void;
|
|
11
12
|
};
|
|
12
|
-
type WebGLUnsupportedReason = "no-document" | "no-webgl" | "reduced-motion" | "context-lost";
|
|
13
|
+
type WebGLUnsupportedReason = "no-document" | "no-webgl" | "software-renderer" | "reduced-motion" | "context-lost";
|
|
13
14
|
|
|
14
15
|
declare const webglRenderer: (options?: WebGLRendererOptions) => EngineFeature;
|
|
15
16
|
|
package/dist/webgl.d.ts
CHANGED
|
@@ -7,9 +7,10 @@ type WebGLRendererOptions = {
|
|
|
7
7
|
glass?: number;
|
|
8
8
|
liftContent?: boolean;
|
|
9
9
|
dpr?: number;
|
|
10
|
+
allowSoftware?: boolean;
|
|
10
11
|
onUnsupported?: (reason: WebGLUnsupportedReason) => void;
|
|
11
12
|
};
|
|
12
|
-
type WebGLUnsupportedReason = "no-document" | "no-webgl" | "reduced-motion" | "context-lost";
|
|
13
|
+
type WebGLUnsupportedReason = "no-document" | "no-webgl" | "software-renderer" | "reduced-motion" | "context-lost";
|
|
13
14
|
|
|
14
15
|
declare const webglRenderer: (options?: WebGLRendererOptions) => EngineFeature;
|
|
15
16
|
|
package/dist/webgl.js
CHANGED
|
@@ -7,6 +7,22 @@ var supportsHighpFragment = (gl) => {
|
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
+
var SOFTWARE = /swiftshader|llvmpipe|softpipe|software|basic render/i;
|
|
11
|
+
var MASKED = /^webkit webgl$/i;
|
|
12
|
+
var rendererName = (gl) => {
|
|
13
|
+
const plain = String(gl.getParameter(gl.RENDERER) ?? "");
|
|
14
|
+
if (plain && !MASKED.test(plain)) return plain;
|
|
15
|
+
const info = gl.getExtension("WEBGL_debug_renderer_info");
|
|
16
|
+
if (!info) return "";
|
|
17
|
+
return String(gl.getParameter(info.UNMASKED_RENDERER_WEBGL) ?? "");
|
|
18
|
+
};
|
|
19
|
+
var drawsOnCpu = (gl) => {
|
|
20
|
+
try {
|
|
21
|
+
return SOFTWARE.test(rendererName(gl));
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
10
26
|
var hasWebGL = () => {
|
|
11
27
|
if (typeof document === "undefined") return false;
|
|
12
28
|
if (typeof WebGLRenderingContext === "undefined" && typeof WebGL2RenderingContext === "undefined") {
|
|
@@ -32,14 +48,16 @@ var createGLHandle = (onLost) => {
|
|
|
32
48
|
canvas.style.position = "fixed";
|
|
33
49
|
canvas.style.left = "0";
|
|
34
50
|
canvas.style.top = "0";
|
|
51
|
+
canvas.style.width = "100%";
|
|
52
|
+
canvas.style.height = "100%";
|
|
35
53
|
canvas.style.pointerEvents = "none";
|
|
36
54
|
const attrs = {
|
|
37
55
|
alpha: true,
|
|
38
56
|
premultipliedAlpha: true,
|
|
39
|
-
antialias:
|
|
57
|
+
antialias: false,
|
|
40
58
|
depth: false,
|
|
41
59
|
stencil: false,
|
|
42
|
-
preserveDrawingBuffer:
|
|
60
|
+
preserveDrawingBuffer: true
|
|
43
61
|
};
|
|
44
62
|
let gl = null;
|
|
45
63
|
let isWebGL2 = false;
|
|
@@ -83,8 +101,6 @@ var resizeDrawingBuffer = (handle, cssWidth, cssHeight, dpr) => {
|
|
|
83
101
|
handle.canvas.width = w;
|
|
84
102
|
handle.canvas.height = h;
|
|
85
103
|
}
|
|
86
|
-
handle.canvas.style.width = `${cssWidth}px`;
|
|
87
|
-
handle.canvas.style.height = `${cssHeight}px`;
|
|
88
104
|
handle.gl.viewport(0, 0, w, h);
|
|
89
105
|
};
|
|
90
106
|
|
|
@@ -100,7 +116,7 @@ precision ${precision} float;
|
|
|
100
116
|
|
|
101
117
|
uniform vec2 u_resolution;
|
|
102
118
|
uniform vec4 u_rect;
|
|
103
|
-
uniform
|
|
119
|
+
uniform vec4 u_radius;
|
|
104
120
|
uniform vec4 u_color;
|
|
105
121
|
uniform float u_shadow;
|
|
106
122
|
uniform float u_bend;
|
|
@@ -113,7 +129,9 @@ uniform sampler2D u_scroll;
|
|
|
113
129
|
uniform vec4 u_scrollRect;
|
|
114
130
|
uniform vec2 u_scrollMap;
|
|
115
131
|
|
|
116
|
-
float roundedBoxSDF(vec2 p, vec2 halfSize,
|
|
132
|
+
float roundedBoxSDF(vec2 p, vec2 halfSize, vec4 radii) {
|
|
133
|
+
vec2 side = p.x < 0.0 ? radii.xw : radii.yz;
|
|
134
|
+
float r = min(p.y < 0.0 ? side.x : side.y, min(halfSize.x, halfSize.y));
|
|
117
135
|
vec2 q = abs(p) - halfSize + r;
|
|
118
136
|
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
|
119
137
|
}
|
|
@@ -129,8 +147,7 @@ void main() {
|
|
|
129
147
|
vec2 p = frag - center;
|
|
130
148
|
p.y -= bend;
|
|
131
149
|
|
|
132
|
-
float
|
|
133
|
-
float d = roundedBoxSDF(p, halfSize, r);
|
|
150
|
+
float d = roundedBoxSDF(p, halfSize, u_radius);
|
|
134
151
|
float surface = 1.0 - smoothstep(-1.0, 1.0, d);
|
|
135
152
|
|
|
136
153
|
vec2 uv = (p + halfSize) / u_rect.zw;
|
|
@@ -254,7 +271,14 @@ var createSurfaceProgram = (gl, highp = true) => {
|
|
|
254
271
|
frame.width * dpr,
|
|
255
272
|
frame.height * dpr
|
|
256
273
|
);
|
|
257
|
-
|
|
274
|
+
const [topLeft, topRight, bottomRight, bottomLeft] = frame.radii;
|
|
275
|
+
gl.uniform4f(
|
|
276
|
+
uRadius,
|
|
277
|
+
topLeft * dpr,
|
|
278
|
+
topRight * dpr,
|
|
279
|
+
bottomRight * dpr,
|
|
280
|
+
bottomLeft * dpr
|
|
281
|
+
);
|
|
258
282
|
gl.uniform4f(uColor, ...frame.color);
|
|
259
283
|
gl.uniform1f(uShadow, frame.shadow);
|
|
260
284
|
gl.uniform1f(uBend, state.bend * dpr);
|
|
@@ -614,6 +638,7 @@ var parseColor = (value) => {
|
|
|
614
638
|
}
|
|
615
639
|
return readColor(value);
|
|
616
640
|
};
|
|
641
|
+
var parentAcrossShadow = (node) => node.parentElement ?? node.getRootNode().host ?? null;
|
|
617
642
|
var parseRadius = (value) => {
|
|
618
643
|
const n = parseFloat(value);
|
|
619
644
|
return Number.isFinite(n) ? n : 0;
|
|
@@ -659,7 +684,12 @@ var webglRenderer = (options = {}) => ({
|
|
|
659
684
|
const cs = getComputedStyle(element);
|
|
660
685
|
return {
|
|
661
686
|
color: parseColor(cs.backgroundColor),
|
|
662
|
-
|
|
687
|
+
radii: [
|
|
688
|
+
parseRadius(cs.borderTopLeftRadius),
|
|
689
|
+
parseRadius(cs.borderTopRightRadius),
|
|
690
|
+
parseRadius(cs.borderBottomRightRadius),
|
|
691
|
+
parseRadius(cs.borderBottomLeftRadius)
|
|
692
|
+
]
|
|
663
693
|
};
|
|
664
694
|
};
|
|
665
695
|
let surfaceStyle = readSurfaceStyle();
|
|
@@ -694,6 +724,12 @@ var webglRenderer = (options = {}) => ({
|
|
|
694
724
|
bail("no-webgl");
|
|
695
725
|
return;
|
|
696
726
|
}
|
|
727
|
+
if (!options.allowSoftware && drawsOnCpu(handle.gl)) {
|
|
728
|
+
handle.destroy();
|
|
729
|
+
handle = null;
|
|
730
|
+
bail("software-renderer");
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
697
733
|
program = createSurfaceProgram(handle.gl, handle.highp);
|
|
698
734
|
if (!program) {
|
|
699
735
|
handle.destroy();
|
|
@@ -704,30 +740,22 @@ var webglRenderer = (options = {}) => ({
|
|
|
704
740
|
const parent = element.parentElement ?? document.body;
|
|
705
741
|
parent.insertBefore(handle.canvas, element);
|
|
706
742
|
let canvasZ = "";
|
|
743
|
+
let canvasPosition = "fixed";
|
|
707
744
|
const followStack = () => {
|
|
708
745
|
if (!handle) return;
|
|
709
|
-
const
|
|
710
|
-
const
|
|
746
|
+
const cs = getComputedStyle(element);
|
|
747
|
+
const position = cs.position === "absolute" ? "absolute" : "fixed";
|
|
748
|
+
if (position !== canvasPosition) {
|
|
749
|
+
canvasPosition = position;
|
|
750
|
+
handle.canvas.style.position = position;
|
|
751
|
+
}
|
|
752
|
+
const next = cs.zIndex && cs.zIndex !== "auto" ? String(Number(cs.zIndex) - 1) : "0";
|
|
711
753
|
if (next === canvasZ) return;
|
|
712
754
|
canvasZ = next;
|
|
713
755
|
handle.canvas.style.zIndex = next;
|
|
714
756
|
};
|
|
715
757
|
followStack();
|
|
716
758
|
suppressDomPaint();
|
|
717
|
-
const readFrame = () => {
|
|
718
|
-
if (!handle) return null;
|
|
719
|
-
const rect = element.getBoundingClientRect();
|
|
720
|
-
if (rect.width <= 0 || rect.height <= 0) return null;
|
|
721
|
-
return {
|
|
722
|
-
x: rect.left,
|
|
723
|
-
y: rect.top,
|
|
724
|
-
width: rect.width,
|
|
725
|
-
height: rect.height,
|
|
726
|
-
radius: surfaceStyle.radius,
|
|
727
|
-
color: surfaceStyle.color,
|
|
728
|
-
shadow: shadowStrength
|
|
729
|
-
};
|
|
730
|
-
};
|
|
731
759
|
const dprOf = () => options.dpr ?? window.devicePixelRatio ?? 1;
|
|
732
760
|
const releaseCapture = () => {
|
|
733
761
|
releaseText?.();
|
|
@@ -751,41 +779,52 @@ var webglRenderer = (options = {}) => ({
|
|
|
751
779
|
capture = next;
|
|
752
780
|
releaseText = hideCapturedText(next.hiddenNodes);
|
|
753
781
|
};
|
|
754
|
-
const scrollLayer = (
|
|
782
|
+
const scrollLayer = (sheet) => {
|
|
755
783
|
const scroll = capture?.scroll;
|
|
756
784
|
const scroller = ctx.scrollContainer;
|
|
757
785
|
if (!scroll || !scroller) return null;
|
|
758
786
|
const box = scroller.getBoundingClientRect();
|
|
759
|
-
const left = box.left + scroller.clientLeft -
|
|
760
|
-
const top = box.top + scroller.clientTop -
|
|
787
|
+
const left = box.left + scroller.clientLeft - sheet.left;
|
|
788
|
+
const top = box.top + scroller.clientTop - sheet.top;
|
|
761
789
|
return {
|
|
762
790
|
texture: scroll.texture,
|
|
763
791
|
rect: [
|
|
764
|
-
left /
|
|
765
|
-
top /
|
|
766
|
-
(left + scroller.clientWidth) /
|
|
767
|
-
(top + scroller.clientHeight) /
|
|
792
|
+
left / sheet.width,
|
|
793
|
+
top / sheet.height,
|
|
794
|
+
(left + scroller.clientWidth) / sheet.width,
|
|
795
|
+
(top + scroller.clientHeight) / sheet.height
|
|
768
796
|
],
|
|
769
797
|
map: [
|
|
770
|
-
|
|
798
|
+
sheet.height / scroll.height,
|
|
771
799
|
(scroll.above + scroller.scrollTop - scroll.top) / scroll.height
|
|
772
800
|
]
|
|
773
801
|
};
|
|
774
802
|
};
|
|
775
803
|
const paint = () => {
|
|
776
804
|
if (disposed || !handle || !program) return;
|
|
777
|
-
const
|
|
778
|
-
|
|
805
|
+
const sheet = element.getBoundingClientRect();
|
|
806
|
+
const area = handle.canvas.getBoundingClientRect();
|
|
807
|
+
if (sheet.width <= 0 || sheet.height <= 0) return;
|
|
808
|
+
if (area.width <= 0 || area.height <= 0) return;
|
|
779
809
|
const dpr = dprOf();
|
|
780
|
-
resizeDrawingBuffer(handle,
|
|
810
|
+
resizeDrawingBuffer(handle, area.width, area.height, dpr);
|
|
781
811
|
const motion = Math.min(1, Math.abs(bend) / MAX_BEND_PX);
|
|
812
|
+
const frame = {
|
|
813
|
+
x: sheet.left - area.left,
|
|
814
|
+
y: sheet.top - area.top,
|
|
815
|
+
width: sheet.width,
|
|
816
|
+
height: sheet.height,
|
|
817
|
+
radii: surfaceStyle.radii,
|
|
818
|
+
color: surfaceStyle.color,
|
|
819
|
+
shadow: shadowStrength
|
|
820
|
+
};
|
|
782
821
|
program.draw(frame, {
|
|
783
822
|
bend,
|
|
784
823
|
dpr,
|
|
785
824
|
sheen: sheenStrength,
|
|
786
825
|
glass: glassStrength * motion,
|
|
787
826
|
content: capture?.texture ?? null,
|
|
788
|
-
scroll: scrollLayer(
|
|
827
|
+
scroll: scrollLayer(sheet)
|
|
789
828
|
});
|
|
790
829
|
};
|
|
791
830
|
const tick = () => {
|
|
@@ -804,6 +843,7 @@ var webglRenderer = (options = {}) => ({
|
|
|
804
843
|
paint();
|
|
805
844
|
running = false;
|
|
806
845
|
frameId = null;
|
|
846
|
+
queueRefresh();
|
|
807
847
|
return;
|
|
808
848
|
}
|
|
809
849
|
frameId = requestAnimationFrame(tick);
|
|
@@ -842,36 +882,71 @@ var webglRenderer = (options = {}) => ({
|
|
|
842
882
|
subtree: true,
|
|
843
883
|
characterData: true
|
|
844
884
|
});
|
|
845
|
-
const
|
|
885
|
+
const onGeometry = () => {
|
|
846
886
|
followStack();
|
|
847
887
|
if (!ctx.isDragging()) paint();
|
|
848
888
|
wake();
|
|
849
|
-
}
|
|
889
|
+
};
|
|
890
|
+
const geometryObserver = new MutationObserver(onGeometry);
|
|
850
891
|
geometryObserver.observe(element, {
|
|
851
892
|
attributes: true,
|
|
852
893
|
attributeFilter: ["style"]
|
|
853
894
|
});
|
|
854
895
|
const refreshSurfaceStyle = () => {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
896
|
+
const moved = geometryObserver.takeRecords().length > 0;
|
|
897
|
+
const style = element.style;
|
|
898
|
+
const transition = style.transition;
|
|
899
|
+
style.transition = "none";
|
|
900
|
+
restoreDom();
|
|
901
|
+
const next = readSurfaceStyle();
|
|
902
|
+
suppressDomPaint();
|
|
903
|
+
void getComputedStyle(element).backgroundColor;
|
|
904
|
+
style.transition = transition;
|
|
905
|
+
geometryObserver.takeRecords();
|
|
906
|
+
const changed = next.radii.some((radius, i) => radius !== surfaceStyle.radii[i]) || next.color.some((channel, i) => channel !== surfaceStyle.color[i]);
|
|
907
|
+
surfaceStyle = next;
|
|
908
|
+
if (!moved) {
|
|
909
|
+
followStack();
|
|
910
|
+
return changed;
|
|
911
|
+
}
|
|
912
|
+
onGeometry();
|
|
913
|
+
return false;
|
|
914
|
+
};
|
|
915
|
+
let refreshQueued = false;
|
|
916
|
+
const queueRefresh = () => {
|
|
917
|
+
if (disposed || refreshQueued) return;
|
|
918
|
+
refreshQueued = true;
|
|
919
|
+
requestAnimationFrame(() => {
|
|
920
|
+
refreshQueued = false;
|
|
921
|
+
if (!disposed && refreshSurfaceStyle()) paint();
|
|
922
|
+
});
|
|
861
923
|
};
|
|
924
|
+
const onThemeSignal = () => {
|
|
925
|
+
if (!ctx.isDragging() && !ctx.isAnimating()) queueRefresh();
|
|
926
|
+
};
|
|
927
|
+
const themeObserver = new MutationObserver(onThemeSignal);
|
|
928
|
+
themeObserver.observe(element, {
|
|
929
|
+
attributes: true,
|
|
930
|
+
attributeFilter: ["class"]
|
|
931
|
+
});
|
|
932
|
+
for (let node = parentAcrossShadow(element); node; node = parentAcrossShadow(node)) {
|
|
933
|
+
themeObserver.observe(node, { attributes: true });
|
|
934
|
+
}
|
|
935
|
+
const scheme = typeof matchMedia === "function" ? matchMedia("(prefers-color-scheme: dark)") : null;
|
|
936
|
+
scheme?.addEventListener?.("change", onThemeSignal);
|
|
862
937
|
const onResize = () => {
|
|
863
938
|
if (disposed) return;
|
|
864
939
|
refreshSurfaceStyle();
|
|
865
940
|
paint();
|
|
866
941
|
};
|
|
867
942
|
window.addEventListener("resize", onResize, { passive: true });
|
|
868
|
-
window.addEventListener("scroll", onResize, { passive: true });
|
|
869
943
|
paint();
|
|
870
944
|
return () => {
|
|
871
945
|
contentObserver.disconnect();
|
|
872
946
|
geometryObserver.disconnect();
|
|
947
|
+
themeObserver.disconnect();
|
|
948
|
+
scheme?.removeEventListener?.("change", onThemeSignal);
|
|
873
949
|
window.removeEventListener("resize", onResize);
|
|
874
|
-
window.removeEventListener("scroll", onResize);
|
|
875
950
|
teardown();
|
|
876
951
|
};
|
|
877
952
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@surdeddd/bottom-sheet",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Bottom sheet, drawer and modal sheet with snap points, spring physics and touch gestures. One engine for React, Vue 3, Svelte 5, Solid, Qwik, Preact and a <bottom-sheet> web component. Accessible, SSR-safe, no dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -340,7 +340,7 @@
|
|
|
340
340
|
{
|
|
341
341
|
"name": "webgl renderer (subpath)",
|
|
342
342
|
"path": "dist/webgl.js",
|
|
343
|
-
"limit": "
|
|
343
|
+
"limit": "6.44 KB",
|
|
344
344
|
"gzip": true
|
|
345
345
|
}
|
|
346
346
|
],
|