@surdeddd/bottom-sheet 0.13.0 → 0.14.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 +33 -0
- package/dist/{BottomSheetCore-CsIjyq7C.d.cts → BottomSheetCore-Cp7dWy91.d.cts} +26 -1
- package/dist/{BottomSheetCore-D16lsa6g.d.ts → BottomSheetCore-DJYwWOqt.d.ts} +26 -1
- package/dist/{BottomSheetEngine-BYjAVrmd.d.cts → BottomSheetEngine-Lm7HIVHv.d.cts} +1 -1
- package/dist/{BottomSheetEngine-YuCNugZn.d.ts → BottomSheetEngine-O5PbeKfe.d.ts} +1 -1
- package/dist/core.cjs +231 -27
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +231 -27
- package/dist/debug.d.cts +1 -1
- package/dist/debug.d.ts +1 -1
- package/dist/element.cjs +300 -102
- package/dist/element.d.cts +2 -2
- package/dist/element.d.ts +2 -2
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +300 -102
- package/dist/features.cjs +6 -50
- package/dist/features.d.cts +2 -2
- package/dist/features.d.ts +2 -2
- package/dist/features.js +6 -50
- package/dist/index-Bb5TRmyg.d.cts +9 -0
- package/dist/index-Cl9ebCP2.d.ts +9 -0
- package/dist/index.cjs +238 -823
- package/dist/index.d.cts +42 -45
- package/dist/index.d.ts +42 -45
- package/dist/index.js +239 -810
- package/dist/integrations/formik.d.cts +1 -1
- package/dist/integrations/formik.d.ts +1 -1
- package/dist/integrations/react-hook-form.d.cts +1 -1
- package/dist/integrations/react-hook-form.d.ts +1 -1
- package/dist/overlay.cjs +5 -5
- package/dist/overlay.js +5 -5
- package/dist/preact.d.cts +2 -2
- package/dist/preact.d.ts +2 -2
- package/dist/qwik-lib/index.qwik.cjs +228 -77
- package/dist/qwik-lib/index.qwik.mjs +228 -77
- package/dist/qwik.cjs +245 -77
- package/dist/qwik.d.cts +4 -2
- package/dist/qwik.d.ts +4 -2
- package/dist/qwik.js +245 -77
- package/dist/react.cjs +250 -79
- package/dist/react.d.cts +3 -4
- package/dist/react.d.ts +3 -4
- package/dist/react.js +250 -79
- package/dist/solid.cjs +251 -77
- package/dist/solid.d.cts +27 -0
- package/dist/solid.d.ts +27 -0
- package/dist/solid.js +251 -77
- package/dist/solid.source.jsx +259 -77
- package/dist/styles.css +24 -4
- package/dist/svelte-core.cjs +237 -77
- package/dist/svelte-core.js +237 -77
- package/dist/svelte-src/BottomSheet.svelte +14 -0
- package/dist/svelte.cjs +247 -77
- package/dist/svelte.d.cts +2 -0
- package/dist/svelte.d.ts +2 -0
- package/dist/svelte.js +247 -77
- package/dist/vue.cjs +253 -77
- package/dist/vue.js +253 -77
- package/dist/webgl.cjs +583 -0
- package/dist/webgl.d.cts +17 -0
- package/dist/webgl.d.ts +17 -0
- package/dist/webgl.js +581 -0
- package/package.json +36 -12
- package/dist/index-DdYLOIIT.d.ts +0 -15
- package/dist/index-dfrzw-lI.d.cts +0 -15
package/dist/webgl.js
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
// src/webgl/gl-context.ts
|
|
2
|
+
var hasWebGL = () => {
|
|
3
|
+
if (typeof document === "undefined") return false;
|
|
4
|
+
if (typeof WebGLRenderingContext === "undefined") return false;
|
|
5
|
+
try {
|
|
6
|
+
const probe = document.createElement("canvas");
|
|
7
|
+
const gl = probe.getContext("webgl", { alpha: true }) ?? probe.getContext("experimental-webgl");
|
|
8
|
+
if (!gl) return false;
|
|
9
|
+
const lose = gl.getExtension(
|
|
10
|
+
"WEBGL_lose_context"
|
|
11
|
+
);
|
|
12
|
+
lose?.loseContext();
|
|
13
|
+
return true;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var createGLHandle = (onLost) => {
|
|
19
|
+
if (typeof document === "undefined") return null;
|
|
20
|
+
const canvas = document.createElement("canvas");
|
|
21
|
+
canvas.setAttribute("aria-hidden", "true");
|
|
22
|
+
canvas.style.position = "fixed";
|
|
23
|
+
canvas.style.left = "0";
|
|
24
|
+
canvas.style.top = "0";
|
|
25
|
+
canvas.style.pointerEvents = "none";
|
|
26
|
+
let gl = null;
|
|
27
|
+
try {
|
|
28
|
+
gl = canvas.getContext("webgl", {
|
|
29
|
+
alpha: true,
|
|
30
|
+
premultipliedAlpha: true,
|
|
31
|
+
antialias: true,
|
|
32
|
+
depth: false,
|
|
33
|
+
stencil: false,
|
|
34
|
+
preserveDrawingBuffer: false
|
|
35
|
+
});
|
|
36
|
+
} catch {
|
|
37
|
+
gl = null;
|
|
38
|
+
}
|
|
39
|
+
if (!gl) return null;
|
|
40
|
+
const handleLost = (e) => {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
onLost();
|
|
43
|
+
};
|
|
44
|
+
canvas.addEventListener("webglcontextlost", handleLost);
|
|
45
|
+
return {
|
|
46
|
+
canvas,
|
|
47
|
+
gl,
|
|
48
|
+
destroy: () => {
|
|
49
|
+
canvas.removeEventListener("webglcontextlost", handleLost);
|
|
50
|
+
const lose = gl?.getExtension("WEBGL_lose_context");
|
|
51
|
+
try {
|
|
52
|
+
lose?.loseContext();
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
canvas.remove();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
var resizeDrawingBuffer = (handle, cssWidth, cssHeight, dpr) => {
|
|
60
|
+
const w = Math.max(1, Math.round(cssWidth * dpr));
|
|
61
|
+
const h = Math.max(1, Math.round(cssHeight * dpr));
|
|
62
|
+
if (handle.canvas.width !== w || handle.canvas.height !== h) {
|
|
63
|
+
handle.canvas.width = w;
|
|
64
|
+
handle.canvas.height = h;
|
|
65
|
+
}
|
|
66
|
+
handle.canvas.style.width = `${cssWidth}px`;
|
|
67
|
+
handle.canvas.style.height = `${cssHeight}px`;
|
|
68
|
+
handle.gl.viewport(0, 0, w, h);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/webgl/surface-program.ts
|
|
72
|
+
var VERTEX_SRC = `
|
|
73
|
+
attribute vec2 a_pos;
|
|
74
|
+
void main() {
|
|
75
|
+
gl_Position = vec4(a_pos, 0.0, 1.0);
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
var FRAGMENT_SRC = `
|
|
79
|
+
precision mediump float;
|
|
80
|
+
|
|
81
|
+
uniform vec2 u_resolution;
|
|
82
|
+
uniform vec4 u_rect;
|
|
83
|
+
uniform float u_radius;
|
|
84
|
+
uniform vec4 u_color;
|
|
85
|
+
uniform float u_shadow;
|
|
86
|
+
uniform float u_bend;
|
|
87
|
+
uniform float u_sheen;
|
|
88
|
+
uniform float u_glass;
|
|
89
|
+
uniform float u_hasContent;
|
|
90
|
+
uniform sampler2D u_content;
|
|
91
|
+
|
|
92
|
+
float roundedBoxSDF(vec2 p, vec2 halfSize, float r) {
|
|
93
|
+
vec2 q = abs(p) - halfSize + r;
|
|
94
|
+
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void main() {
|
|
98
|
+
vec2 frag = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y);
|
|
99
|
+
vec2 center = u_rect.xy + u_rect.zw * 0.5;
|
|
100
|
+
vec2 halfSize = u_rect.zw * 0.5;
|
|
101
|
+
|
|
102
|
+
float across = clamp((frag.x - u_rect.x) / max(u_rect.z, 1.0), 0.0, 1.0);
|
|
103
|
+
float bend = sin(across * 3.14159265) * u_bend;
|
|
104
|
+
|
|
105
|
+
vec2 p = frag - center;
|
|
106
|
+
p.y -= bend;
|
|
107
|
+
|
|
108
|
+
float r = min(u_radius, min(halfSize.x, halfSize.y));
|
|
109
|
+
float d = roundedBoxSDF(p, halfSize, r);
|
|
110
|
+
float surface = 1.0 - smoothstep(-1.0, 1.0, d);
|
|
111
|
+
|
|
112
|
+
vec2 uv = (p + halfSize) / u_rect.zw;
|
|
113
|
+
float down = clamp(uv.y, 0.0, 1.0);
|
|
114
|
+
|
|
115
|
+
vec2 glassUv = uv;
|
|
116
|
+
glassUv.x += sin(uv.y * 9.0 + u_bend * 0.08) * u_glass * 0.004;
|
|
117
|
+
glassUv.y += u_glass * 0.002 * sin(uv.x * 7.0);
|
|
118
|
+
|
|
119
|
+
vec4 content = vec4(0.0);
|
|
120
|
+
if (u_hasContent > 0.5 &&
|
|
121
|
+
glassUv.x > 0.0 && glassUv.x < 1.0 &&
|
|
122
|
+
glassUv.y > 0.0 && glassUv.y < 1.0) {
|
|
123
|
+
content = texture2D(u_content, glassUv);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
float edge = 1.0 - smoothstep(0.0, 2.5, abs(d));
|
|
127
|
+
float topLight = pow(1.0 - down, 3.0);
|
|
128
|
+
float sheen = (edge * 0.55 + topLight * 0.25) * u_sheen;
|
|
129
|
+
|
|
130
|
+
vec3 panelRgb = (u_color.rgb + vec3(sheen)) * u_color.a;
|
|
131
|
+
float panelA = u_color.a;
|
|
132
|
+
|
|
133
|
+
vec3 rgb = content.rgb + panelRgb * (1.0 - content.a);
|
|
134
|
+
float alpha = content.a + panelA * (1.0 - content.a);
|
|
135
|
+
|
|
136
|
+
rgb *= surface;
|
|
137
|
+
alpha *= surface;
|
|
138
|
+
|
|
139
|
+
float shadow = (1.0 - smoothstep(0.0, 24.0, d)) * u_shadow * (1.0 - surface);
|
|
140
|
+
alpha += shadow * 0.28;
|
|
141
|
+
|
|
142
|
+
gl_FragColor = vec4(rgb, alpha);
|
|
143
|
+
}
|
|
144
|
+
`;
|
|
145
|
+
var compile = (gl, type, src) => {
|
|
146
|
+
const shader = gl.createShader(type);
|
|
147
|
+
if (!shader) return null;
|
|
148
|
+
gl.shaderSource(shader, src);
|
|
149
|
+
gl.compileShader(shader);
|
|
150
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
151
|
+
gl.deleteShader(shader);
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
return shader;
|
|
155
|
+
};
|
|
156
|
+
var createSurfaceProgram = (gl) => {
|
|
157
|
+
const vs = compile(gl, gl.VERTEX_SHADER, VERTEX_SRC);
|
|
158
|
+
const fs = compile(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC);
|
|
159
|
+
if (!vs || !fs) return null;
|
|
160
|
+
const program = gl.createProgram();
|
|
161
|
+
if (!program) return null;
|
|
162
|
+
gl.attachShader(program, vs);
|
|
163
|
+
gl.attachShader(program, fs);
|
|
164
|
+
gl.linkProgram(program);
|
|
165
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
166
|
+
gl.deleteProgram(program);
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
const buffer = gl.createBuffer();
|
|
170
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
171
|
+
gl.bufferData(
|
|
172
|
+
gl.ARRAY_BUFFER,
|
|
173
|
+
new Float32Array([-1, -1, 3, -1, -1, 3]),
|
|
174
|
+
gl.STATIC_DRAW
|
|
175
|
+
);
|
|
176
|
+
const aPos = gl.getAttribLocation(program, "a_pos");
|
|
177
|
+
const uResolution = gl.getUniformLocation(program, "u_resolution");
|
|
178
|
+
const uRect = gl.getUniformLocation(program, "u_rect");
|
|
179
|
+
const uRadius = gl.getUniformLocation(program, "u_radius");
|
|
180
|
+
const uColor = gl.getUniformLocation(program, "u_color");
|
|
181
|
+
const uShadow = gl.getUniformLocation(program, "u_shadow");
|
|
182
|
+
const uBend = gl.getUniformLocation(program, "u_bend");
|
|
183
|
+
const uSheen = gl.getUniformLocation(program, "u_sheen");
|
|
184
|
+
const uGlass = gl.getUniformLocation(program, "u_glass");
|
|
185
|
+
const uHasContent = gl.getUniformLocation(program, "u_hasContent");
|
|
186
|
+
const uContent = gl.getUniformLocation(program, "u_content");
|
|
187
|
+
return {
|
|
188
|
+
draw: (frame, state) => {
|
|
189
|
+
const { drawingBufferWidth: w, drawingBufferHeight: h } = gl;
|
|
190
|
+
const dpr = state.dpr;
|
|
191
|
+
gl.clearColor(0, 0, 0, 0);
|
|
192
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
193
|
+
gl.enable(gl.BLEND);
|
|
194
|
+
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
195
|
+
gl.useProgram(program);
|
|
196
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
197
|
+
gl.enableVertexAttribArray(aPos);
|
|
198
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
|
|
199
|
+
gl.uniform2f(uResolution, w, h);
|
|
200
|
+
gl.uniform4f(
|
|
201
|
+
uRect,
|
|
202
|
+
frame.x * dpr,
|
|
203
|
+
frame.y * dpr,
|
|
204
|
+
frame.width * dpr,
|
|
205
|
+
frame.height * dpr
|
|
206
|
+
);
|
|
207
|
+
gl.uniform1f(uRadius, frame.radius * dpr);
|
|
208
|
+
gl.uniform4f(uColor, ...frame.color);
|
|
209
|
+
gl.uniform1f(uShadow, frame.shadow);
|
|
210
|
+
gl.uniform1f(uBend, state.bend * dpr);
|
|
211
|
+
gl.uniform1f(uSheen, state.sheen);
|
|
212
|
+
gl.uniform1f(uGlass, state.glass);
|
|
213
|
+
if (state.content) {
|
|
214
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
215
|
+
gl.bindTexture(gl.TEXTURE_2D, state.content);
|
|
216
|
+
gl.uniform1i(uContent, 0);
|
|
217
|
+
gl.uniform1f(uHasContent, 1);
|
|
218
|
+
} else {
|
|
219
|
+
gl.uniform1f(uHasContent, 0);
|
|
220
|
+
}
|
|
221
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
222
|
+
},
|
|
223
|
+
destroy: () => {
|
|
224
|
+
gl.deleteBuffer(buffer);
|
|
225
|
+
gl.deleteProgram(program);
|
|
226
|
+
gl.deleteShader(vs);
|
|
227
|
+
gl.deleteShader(fs);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// src/webgl/content-texture.ts
|
|
233
|
+
var SKIP_TAGS = /* @__PURE__ */ new Set([
|
|
234
|
+
"INPUT",
|
|
235
|
+
"TEXTAREA",
|
|
236
|
+
"SELECT",
|
|
237
|
+
"IMG",
|
|
238
|
+
"SVG",
|
|
239
|
+
"CANVAS",
|
|
240
|
+
"VIDEO",
|
|
241
|
+
"IFRAME",
|
|
242
|
+
"BUTTON"
|
|
243
|
+
]);
|
|
244
|
+
var isRenderable = (el) => {
|
|
245
|
+
if (SKIP_TAGS.has(el.tagName)) return false;
|
|
246
|
+
const cs = getComputedStyle(el);
|
|
247
|
+
if (cs.visibility === "hidden" || cs.display === "none") return false;
|
|
248
|
+
if (parseFloat(cs.opacity) < 0.05) return false;
|
|
249
|
+
return true;
|
|
250
|
+
};
|
|
251
|
+
var directText = (el) => {
|
|
252
|
+
let out = "";
|
|
253
|
+
for (const node of Array.from(el.childNodes)) {
|
|
254
|
+
if (node.nodeType === Node.TEXT_NODE) out += node.textContent ?? "";
|
|
255
|
+
}
|
|
256
|
+
return out.trim();
|
|
257
|
+
};
|
|
258
|
+
var wrapLines = (ctx, text, maxWidth) => {
|
|
259
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
260
|
+
if (!words.length) return [];
|
|
261
|
+
const lines = [];
|
|
262
|
+
let line = words[0];
|
|
263
|
+
for (let i = 1; i < words.length; i++) {
|
|
264
|
+
const candidate = `${line} ${words[i]}`;
|
|
265
|
+
if (ctx.measureText(candidate).width <= maxWidth) line = candidate;
|
|
266
|
+
else {
|
|
267
|
+
lines.push(line);
|
|
268
|
+
line = words[i];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
lines.push(line);
|
|
272
|
+
return lines;
|
|
273
|
+
};
|
|
274
|
+
var captureContent = (gl, root, dpr) => {
|
|
275
|
+
const rootRect = root.getBoundingClientRect();
|
|
276
|
+
const w = Math.max(1, Math.round(rootRect.width * dpr));
|
|
277
|
+
const h = Math.max(1, Math.round(rootRect.height * dpr));
|
|
278
|
+
if (w < 2 || h < 2) return null;
|
|
279
|
+
const surface = document.createElement("canvas");
|
|
280
|
+
surface.width = w;
|
|
281
|
+
surface.height = h;
|
|
282
|
+
const ctx = surface.getContext("2d");
|
|
283
|
+
if (!ctx) return null;
|
|
284
|
+
ctx.scale(dpr, dpr);
|
|
285
|
+
const hiddenNodes = [];
|
|
286
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
287
|
+
let painted = 0;
|
|
288
|
+
while (walker.nextNode()) {
|
|
289
|
+
const el = walker.currentNode;
|
|
290
|
+
if (!isRenderable(el)) continue;
|
|
291
|
+
const text = directText(el);
|
|
292
|
+
if (!text) continue;
|
|
293
|
+
const rect = el.getBoundingClientRect();
|
|
294
|
+
if (rect.width < 1 || rect.height < 1) continue;
|
|
295
|
+
const cs = getComputedStyle(el);
|
|
296
|
+
ctx.font = `${cs.fontStyle} ${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`;
|
|
297
|
+
ctx.fillStyle = cs.color;
|
|
298
|
+
ctx.textBaseline = "top";
|
|
299
|
+
const padLeft = parseFloat(cs.paddingLeft) || 0;
|
|
300
|
+
const padTop = parseFloat(cs.paddingTop) || 0;
|
|
301
|
+
const innerWidth = Math.max(
|
|
302
|
+
1,
|
|
303
|
+
rect.width - padLeft - (parseFloat(cs.paddingRight) || 0)
|
|
304
|
+
);
|
|
305
|
+
const lineHeight = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.4;
|
|
306
|
+
const x = rect.left - rootRect.left + padLeft;
|
|
307
|
+
const y = rect.top - rootRect.top + padTop;
|
|
308
|
+
const lines = wrapLines(ctx, text, innerWidth);
|
|
309
|
+
lines.forEach((line, i) => {
|
|
310
|
+
const lineY = y + i * lineHeight;
|
|
311
|
+
if (lineY > rootRect.height) return;
|
|
312
|
+
let lineX = x;
|
|
313
|
+
if (cs.textAlign === "center") {
|
|
314
|
+
lineX = x + (innerWidth - ctx.measureText(line).width) / 2;
|
|
315
|
+
} else if (cs.textAlign === "right") {
|
|
316
|
+
lineX = x + innerWidth - ctx.measureText(line).width;
|
|
317
|
+
}
|
|
318
|
+
ctx.fillText(line, lineX, lineY);
|
|
319
|
+
});
|
|
320
|
+
if (lines.length) {
|
|
321
|
+
painted++;
|
|
322
|
+
hiddenNodes.push(el);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (!painted) return null;
|
|
326
|
+
const texture = gl.createTexture();
|
|
327
|
+
if (!texture) return null;
|
|
328
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
329
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
330
|
+
gl.texImage2D(
|
|
331
|
+
gl.TEXTURE_2D,
|
|
332
|
+
0,
|
|
333
|
+
gl.RGBA,
|
|
334
|
+
gl.RGBA,
|
|
335
|
+
gl.UNSIGNED_BYTE,
|
|
336
|
+
surface
|
|
337
|
+
);
|
|
338
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
339
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
340
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
341
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
342
|
+
return { texture, width: w, height: h, hiddenNodes };
|
|
343
|
+
};
|
|
344
|
+
var hideCapturedText = (nodes) => {
|
|
345
|
+
const restore = nodes.map((el) => ({ el, prev: el.style.color }));
|
|
346
|
+
for (const { el } of restore) el.style.color = "transparent";
|
|
347
|
+
return () => {
|
|
348
|
+
for (const { el, prev } of restore) el.style.color = prev;
|
|
349
|
+
};
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// src/webgl/index.ts
|
|
353
|
+
var DEFAULT_JELLY = 0.5;
|
|
354
|
+
var DEFAULT_SHADOW = 1;
|
|
355
|
+
var DEFAULT_SHEEN = 0.35;
|
|
356
|
+
var DEFAULT_GLASS = 0.6;
|
|
357
|
+
var MAX_BEND_PX = 22;
|
|
358
|
+
var BEND_DECAY_HELD = 0.86;
|
|
359
|
+
var BEND_DECAY_FREE = 0.62;
|
|
360
|
+
var BEND_REST = 0.35;
|
|
361
|
+
var prefersReducedMotion = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
362
|
+
var parseColor = (value) => {
|
|
363
|
+
const m = value.match(/rgba?\(([^)]+)\)/);
|
|
364
|
+
if (!m) return [1, 1, 1, 1];
|
|
365
|
+
const parts = m[1].split(",").map((p) => parseFloat(p.trim()));
|
|
366
|
+
const [r = 255, g = 255, b = 255, a = 1] = parts;
|
|
367
|
+
return [r / 255, g / 255, b / 255, a];
|
|
368
|
+
};
|
|
369
|
+
var parseRadius = (value) => {
|
|
370
|
+
const n = parseFloat(value);
|
|
371
|
+
return Number.isFinite(n) ? n : 0;
|
|
372
|
+
};
|
|
373
|
+
var webglRenderer = (options = {}) => ({
|
|
374
|
+
name: "webgl-renderer",
|
|
375
|
+
stage: "post",
|
|
376
|
+
install: (ctx) => {
|
|
377
|
+
const bail = (reason) => {
|
|
378
|
+
options.onUnsupported?.(reason);
|
|
379
|
+
};
|
|
380
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
381
|
+
bail("no-document");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (prefersReducedMotion()) {
|
|
385
|
+
bail("reduced-motion");
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (!hasWebGL()) {
|
|
389
|
+
bail("no-webgl");
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const element = ctx.element;
|
|
393
|
+
const jelly = options.jelly ?? DEFAULT_JELLY;
|
|
394
|
+
const shadowStrength = options.shadow ?? DEFAULT_SHADOW;
|
|
395
|
+
const sheenStrength = options.sheen ?? DEFAULT_SHEEN;
|
|
396
|
+
const glassStrength = options.glass ?? DEFAULT_GLASS;
|
|
397
|
+
const liftContent = options.liftContent !== false;
|
|
398
|
+
let handle = null;
|
|
399
|
+
let program = null;
|
|
400
|
+
let frameId = null;
|
|
401
|
+
let running = false;
|
|
402
|
+
let bend = 0;
|
|
403
|
+
let disposed = false;
|
|
404
|
+
let capture = null;
|
|
405
|
+
let releaseText = null;
|
|
406
|
+
const painted = {
|
|
407
|
+
background: element.style.background,
|
|
408
|
+
boxShadow: element.style.boxShadow
|
|
409
|
+
};
|
|
410
|
+
const readSurfaceStyle = () => {
|
|
411
|
+
const cs = getComputedStyle(element);
|
|
412
|
+
return {
|
|
413
|
+
color: parseColor(cs.backgroundColor),
|
|
414
|
+
radius: parseRadius(cs.borderTopLeftRadius)
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
let surfaceStyle = readSurfaceStyle();
|
|
418
|
+
const restoreDom = () => {
|
|
419
|
+
element.style.background = painted.background;
|
|
420
|
+
element.style.boxShadow = painted.boxShadow;
|
|
421
|
+
element.removeAttribute("data-bs-webgl");
|
|
422
|
+
};
|
|
423
|
+
const suppressDomPaint = () => {
|
|
424
|
+
element.setAttribute("data-bs-webgl", "on");
|
|
425
|
+
element.style.background = "transparent";
|
|
426
|
+
element.style.boxShadow = "none";
|
|
427
|
+
};
|
|
428
|
+
const teardown = (reason) => {
|
|
429
|
+
if (disposed) return;
|
|
430
|
+
disposed = true;
|
|
431
|
+
running = false;
|
|
432
|
+
if (frameId !== null) {
|
|
433
|
+
cancelAnimationFrame(frameId);
|
|
434
|
+
frameId = null;
|
|
435
|
+
}
|
|
436
|
+
releaseCapture();
|
|
437
|
+
program?.destroy();
|
|
438
|
+
program = null;
|
|
439
|
+
handle?.destroy();
|
|
440
|
+
handle = null;
|
|
441
|
+
restoreDom();
|
|
442
|
+
if (reason) bail(reason);
|
|
443
|
+
};
|
|
444
|
+
handle = createGLHandle(() => teardown("context-lost"));
|
|
445
|
+
if (!handle) {
|
|
446
|
+
bail("no-webgl");
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
program = createSurfaceProgram(handle.gl);
|
|
450
|
+
if (!program) {
|
|
451
|
+
handle.destroy();
|
|
452
|
+
handle = null;
|
|
453
|
+
bail("no-webgl");
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const parent = element.parentElement ?? document.body;
|
|
457
|
+
parent.insertBefore(handle.canvas, element);
|
|
458
|
+
const elementZ = getComputedStyle(element).zIndex;
|
|
459
|
+
handle.canvas.style.zIndex = elementZ && elementZ !== "auto" ? String(Number(elementZ) - 1) : "0";
|
|
460
|
+
suppressDomPaint();
|
|
461
|
+
const readFrame = () => {
|
|
462
|
+
if (!handle) return null;
|
|
463
|
+
const rect = element.getBoundingClientRect();
|
|
464
|
+
if (rect.width <= 0 || rect.height <= 0) return null;
|
|
465
|
+
return {
|
|
466
|
+
x: rect.left,
|
|
467
|
+
y: rect.top,
|
|
468
|
+
width: rect.width,
|
|
469
|
+
height: rect.height,
|
|
470
|
+
radius: surfaceStyle.radius,
|
|
471
|
+
color: surfaceStyle.color,
|
|
472
|
+
shadow: shadowStrength
|
|
473
|
+
};
|
|
474
|
+
};
|
|
475
|
+
const dprOf = () => options.dpr ?? window.devicePixelRatio ?? 1;
|
|
476
|
+
const releaseCapture = () => {
|
|
477
|
+
releaseText?.();
|
|
478
|
+
releaseText = null;
|
|
479
|
+
if (capture && handle) handle.gl.deleteTexture(capture.texture);
|
|
480
|
+
capture = null;
|
|
481
|
+
};
|
|
482
|
+
const takeCapture = () => {
|
|
483
|
+
if (!liftContent || disposed || !handle || capture) return;
|
|
484
|
+
const next = captureContent(handle.gl, element, dprOf());
|
|
485
|
+
if (!next) return;
|
|
486
|
+
capture = next;
|
|
487
|
+
releaseText = hideCapturedText(next.hiddenNodes);
|
|
488
|
+
};
|
|
489
|
+
const paint = () => {
|
|
490
|
+
if (disposed || !handle || !program) return;
|
|
491
|
+
const frame = readFrame();
|
|
492
|
+
if (!frame) return;
|
|
493
|
+
const dpr = dprOf();
|
|
494
|
+
resizeDrawingBuffer(handle, window.innerWidth, window.innerHeight, dpr);
|
|
495
|
+
const motion = Math.min(1, Math.abs(bend) / MAX_BEND_PX);
|
|
496
|
+
program.draw(frame, {
|
|
497
|
+
bend,
|
|
498
|
+
dpr,
|
|
499
|
+
sheen: sheenStrength,
|
|
500
|
+
glass: glassStrength * motion,
|
|
501
|
+
content: capture?.texture ?? null
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
const tick = () => {
|
|
505
|
+
if (disposed) return;
|
|
506
|
+
paint();
|
|
507
|
+
const held = ctx.isDragging();
|
|
508
|
+
bend *= held ? BEND_DECAY_HELD : BEND_DECAY_FREE;
|
|
509
|
+
const settled = !held && !ctx.isAnimating() && Math.abs(bend) < BEND_REST;
|
|
510
|
+
if (settled) {
|
|
511
|
+
bend = 0;
|
|
512
|
+
releaseCapture();
|
|
513
|
+
paint();
|
|
514
|
+
running = false;
|
|
515
|
+
frameId = null;
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
frameId = requestAnimationFrame(tick);
|
|
519
|
+
};
|
|
520
|
+
const wake = () => {
|
|
521
|
+
if (disposed || running) return;
|
|
522
|
+
running = true;
|
|
523
|
+
frameId = requestAnimationFrame(tick);
|
|
524
|
+
};
|
|
525
|
+
ctx.addTeardown(
|
|
526
|
+
ctx.on("drag", (payload) => {
|
|
527
|
+
const velocity = payload.delta ?? 0;
|
|
528
|
+
bend = Math.max(
|
|
529
|
+
-MAX_BEND_PX,
|
|
530
|
+
Math.min(MAX_BEND_PX, velocity * jelly * 0.35)
|
|
531
|
+
);
|
|
532
|
+
wake();
|
|
533
|
+
})
|
|
534
|
+
);
|
|
535
|
+
ctx.addTeardown(
|
|
536
|
+
ctx.on("dragstart", () => {
|
|
537
|
+
takeCapture();
|
|
538
|
+
wake();
|
|
539
|
+
})
|
|
540
|
+
);
|
|
541
|
+
ctx.addTeardown(ctx.on("dragend", wake));
|
|
542
|
+
ctx.addTeardown(ctx.on("progress", wake));
|
|
543
|
+
ctx.addTeardown(ctx.on("snap", wake));
|
|
544
|
+
const contentObserver = new MutationObserver(() => {
|
|
545
|
+
if (!capture) return;
|
|
546
|
+
releaseCapture();
|
|
547
|
+
takeCapture();
|
|
548
|
+
});
|
|
549
|
+
contentObserver.observe(element, {
|
|
550
|
+
childList: true,
|
|
551
|
+
subtree: true,
|
|
552
|
+
characterData: true
|
|
553
|
+
});
|
|
554
|
+
const refreshSurfaceStyle = () => {
|
|
555
|
+
if (disposed) return;
|
|
556
|
+
element.style.background = painted.background;
|
|
557
|
+
element.style.boxShadow = painted.boxShadow;
|
|
558
|
+
surfaceStyle = readSurfaceStyle();
|
|
559
|
+
element.style.background = "transparent";
|
|
560
|
+
element.style.boxShadow = "none";
|
|
561
|
+
};
|
|
562
|
+
const onResize = () => {
|
|
563
|
+
if (disposed) return;
|
|
564
|
+
refreshSurfaceStyle();
|
|
565
|
+
paint();
|
|
566
|
+
};
|
|
567
|
+
window.addEventListener("resize", onResize, { passive: true });
|
|
568
|
+
window.addEventListener("scroll", onResize, { passive: true });
|
|
569
|
+
paint();
|
|
570
|
+
return () => {
|
|
571
|
+
contentObserver.disconnect();
|
|
572
|
+
window.removeEventListener("resize", onResize);
|
|
573
|
+
window.removeEventListener("scroll", onResize);
|
|
574
|
+
teardown();
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
export { webglRenderer };
|
|
580
|
+
//# sourceMappingURL=webgl.js.map
|
|
581
|
+
//# sourceMappingURL=webgl.js.map
|