@weasel-js/hud 1.0.0 → 1.0.2
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/dist/attach.d.ts.map +1 -1
- package/dist/index.js +37 -29
- package/dist/index.js.map +1 -1
- package/dist/loupe/createLoupe.d.ts.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/{tool-Cvy1MwFJ.js → tool-DyPy2h0T.js} +57 -49
- package/dist/tool-DyPy2h0T.js.map +1 -0
- package/dist/widget.d.ts +5 -0
- package/dist/widget.d.ts.map +1 -1
- package/dist/widgets/button.d.ts +2 -0
- package/dist/widgets/button.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/tool-Cvy1MwFJ.js.map +0 -1
package/dist/attach.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAA+B,MAAM,iBAAiB,CAAC;AAOvF,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjF,MAAM,WAAW,gBAAgB;IAC/B;2EACuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"attach.d.ts","sourceRoot":"","sources":["../src/attach.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAA+B,MAAM,iBAAiB,CAAC;AAOvF,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjF,MAAM,WAAW,gBAAgB;IAC/B;2EACuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,gBAAqB,GAC7B,MAAM,IAAI,CAwHZ"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "./tool-
|
|
1
|
+
import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "./tool-DyPy2h0T.js";
|
|
2
2
|
import { createViewportLayer as u, screenToWorld as d, viewToTransform as f } from "@weasel-js/core";
|
|
3
3
|
//#region src/loupe/innerView.ts
|
|
4
4
|
function p(e, t, n, r) {
|
|
@@ -33,25 +33,25 @@ function g(e) {
|
|
|
33
33
|
let { hud: t, element: n, source: r, requestRedraw: i } = e, a = e.mode ?? "vector", o = e.factor ?? 8, s = {
|
|
34
34
|
x: 0,
|
|
35
35
|
y: 0
|
|
36
|
-
}, c = null, l = null, h = !1, g = e.bounds ?? {
|
|
36
|
+
}, c = null, l = null, h = !1, g = !1, _ = !1, v = e.bounds ?? {
|
|
37
37
|
x: 24,
|
|
38
38
|
y: 24,
|
|
39
39
|
w: 220,
|
|
40
40
|
h: 200
|
|
41
|
-
},
|
|
41
|
+
}, y = (e) => a === "vector" ? b(e) : x(e), b = (t) => {
|
|
42
42
|
let n = d(s.x, s.y, f(t.view)), i = p({
|
|
43
43
|
x: n[0],
|
|
44
44
|
y: n[1]
|
|
45
45
|
}, t.view, t.rect, o);
|
|
46
46
|
return u({
|
|
47
|
-
id: `${
|
|
47
|
+
id: `${w.id}:lens`,
|
|
48
48
|
label: "Loupe content",
|
|
49
49
|
source: r,
|
|
50
50
|
view: i,
|
|
51
51
|
bounds: () => t.rect,
|
|
52
52
|
background: e.background ?? t.tokens["--wzl-surface"]
|
|
53
53
|
}).draw(t.data, t.view, t.dims);
|
|
54
|
-
},
|
|
54
|
+
}, x = (e) => l ? [{
|
|
55
55
|
kind: "image",
|
|
56
56
|
image: l,
|
|
57
57
|
x: e.rect.x,
|
|
@@ -59,22 +59,30 @@ function g(e) {
|
|
|
59
59
|
w: e.rect.w,
|
|
60
60
|
h: e.rect.h,
|
|
61
61
|
sampling: "nearest"
|
|
62
|
-
}] : [],
|
|
63
|
-
if (a !== "pixel"
|
|
62
|
+
}] : [], S = () => {
|
|
63
|
+
if (_ || a !== "pixel") return;
|
|
64
|
+
if (h) {
|
|
65
|
+
g = !0;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
64
68
|
let e = n.getContext("webgl2");
|
|
65
69
|
if (!e) return;
|
|
66
70
|
let t = n.getBoundingClientRect();
|
|
67
71
|
if (t.width === 0) return;
|
|
68
|
-
let r = n.width / t.width, c =
|
|
72
|
+
let r = n.width / t.width, c = w.contentRect, u = Math.max(1, Math.round(c.w * r / o)), d = Math.max(1, Math.round(c.h * r / o)), f = m(e, {
|
|
69
73
|
width: n.width,
|
|
70
74
|
height: n.height
|
|
71
75
|
}, s, r, u, d);
|
|
72
|
-
h = !0, createImageBitmap(f).then((e) => {
|
|
73
|
-
|
|
76
|
+
h = !0, g = !1, createImageBitmap(f).then((e) => {
|
|
77
|
+
if (_) {
|
|
78
|
+
e.close();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
l?.close(), l = e, h = !1, i(), g && S();
|
|
74
82
|
}).catch(() => {
|
|
75
|
-
h = !1;
|
|
83
|
+
h = !1, g && S();
|
|
76
84
|
});
|
|
77
|
-
},
|
|
85
|
+
}, C = () => {
|
|
78
86
|
let t = n.getContext("webgl2");
|
|
79
87
|
if (!t) return;
|
|
80
88
|
let r = n.getBoundingClientRect();
|
|
@@ -88,30 +96,30 @@ function g(e) {
|
|
|
88
96
|
a.data[2]
|
|
89
97
|
].map((e) => e.toString(16).padStart(2, "0")).join("");
|
|
90
98
|
o !== c && (c = o, e.onColorChange?.(o));
|
|
91
|
-
},
|
|
99
|
+
}, w = t.window({
|
|
92
100
|
id: "weasel-loupe",
|
|
93
|
-
x:
|
|
94
|
-
y:
|
|
95
|
-
w:
|
|
96
|
-
h:
|
|
101
|
+
x: v.x,
|
|
102
|
+
y: v.y,
|
|
103
|
+
w: v.w,
|
|
104
|
+
h: v.h,
|
|
97
105
|
title: e.title ?? "Loupe",
|
|
98
106
|
titlebar: e.titlebar,
|
|
99
|
-
content:
|
|
107
|
+
content: y,
|
|
100
108
|
onResize: () => {
|
|
101
|
-
|
|
109
|
+
S();
|
|
102
110
|
},
|
|
103
111
|
...e.onClose ? { onClose: e.onClose } : {}
|
|
104
|
-
}),
|
|
112
|
+
}), T = (e) => {
|
|
105
113
|
let t = n.getBoundingClientRect();
|
|
106
|
-
|
|
114
|
+
E({
|
|
107
115
|
x: e.clientX - t.left,
|
|
108
116
|
y: e.clientY - t.top
|
|
109
117
|
});
|
|
110
|
-
},
|
|
111
|
-
|
|
118
|
+
}, E = (e) => {
|
|
119
|
+
w.hidden || w.hitTest(e.x, e.y) || (s = e, C(), a === "pixel" && S(), i());
|
|
112
120
|
};
|
|
113
|
-
return n.addEventListener("pointermove",
|
|
114
|
-
window:
|
|
121
|
+
return n.addEventListener("pointermove", T), {
|
|
122
|
+
window: w,
|
|
115
123
|
get mode() {
|
|
116
124
|
return a;
|
|
117
125
|
},
|
|
@@ -125,14 +133,14 @@ function g(e) {
|
|
|
125
133
|
return c;
|
|
126
134
|
},
|
|
127
135
|
setMode(e) {
|
|
128
|
-
e !== a && (a = e, a === "pixel" &&
|
|
136
|
+
e !== a && (a = e, a === "pixel" && S(), i());
|
|
129
137
|
},
|
|
130
138
|
setFactor(e) {
|
|
131
|
-
o = e, a === "pixel" &&
|
|
139
|
+
o = e, a === "pixel" && S(), i();
|
|
132
140
|
},
|
|
133
|
-
aimAt:
|
|
141
|
+
aimAt: E,
|
|
134
142
|
dispose() {
|
|
135
|
-
n.removeEventListener("pointermove",
|
|
143
|
+
_ = !0, n.removeEventListener("pointermove", T), l?.close(), l = null, w.dispose();
|
|
136
144
|
}
|
|
137
145
|
};
|
|
138
146
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/loupe/innerView.ts","../src/loupe/readback.ts","../src/loupe/createLoupe.ts"],"sourcesContent":["import type { View } from '@weasel-js/core';\nimport type { WidgetBounds } from '../widget';\n\n/**\n * The inner `View` a loupe renders its content through: the outer view's\n * magnification times `factor`, positioned so `target` sits at the center of\n * a viewport the size of `rect`.\n */\nexport function loupeInnerView(\n target: { x: number; y: number },\n outer: View,\n rect: WidgetBounds,\n factor: number,\n): View {\n const scale = { x: outer.scale.x * factor, y: outer.scale.y * factor };\n return {\n x: target.x - rect.w / 2 / scale.x,\n y: target.y - rect.h / 2 / scale.y,\n scale,\n };\n}\n","/**\n * Read a `rw × rh` device-pixel region of the drawing buffer centered on\n * `pointer` (CSS px relative to the canvas), returned top-down.\n *\n * GL reports rows bottom-up; every consumer here wants top-down, so both the\n * read origin and the returned rows are flipped.\n */\nexport function readbackRegion(\n gl: WebGL2RenderingContext,\n buffer: { width: number; height: number },\n pointer: { x: number; y: number },\n dpr: number,\n rw: number,\n rh: number,\n): ImageData {\n const cx = Math.round(pointer.x * dpr);\n const cy = Math.round(pointer.y * dpr);\n const gx = clamp(cx - Math.floor(rw / 2), 0, Math.max(0, buffer.width - rw));\n const gyTop = clamp(cy - Math.floor(rh / 2), 0, Math.max(0, buffer.height - rh));\n const gy = buffer.height - gyTop - rh;\n\n const raw = new Uint8Array(rw * rh * 4);\n gl.readPixels(gx, gy, rw, rh, gl.RGBA, gl.UNSIGNED_BYTE, raw);\n\n const flipped = new Uint8ClampedArray(rw * rh * 4);\n const stride = rw * 4;\n for (let row = 0; row < rh; row++) {\n const src = (rh - 1 - row) * stride;\n flipped.set(raw.subarray(src, src + stride), row * stride);\n }\n return new ImageData(flipped, rw, rh);\n}\n\nfunction clamp(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v;\n}\n","import {\n createViewportLayer, screenToWorld, viewToTransform,\n type RenderLayer, type View,\n} from '@weasel-js/core';\nimport type { DrawCommand } from '@weasel-js/core/renderer';\nimport type { Hud } from '../hud';\nimport type { WindowWidget } from '../widgets/window/window';\nimport type { HudContentCtx, WidgetBounds } from '../widget';\nimport { loupeInnerView } from './innerView';\nimport { readbackRegion } from './readback';\n\nexport type LoupeMode = 'vector' | 'pixel';\n\nexport interface LoupeOptions {\n hud: Hud;\n /** The live canvas. Supplies the GL context for pixel mode and the pointer\n * feed for aiming. */\n element: HTMLCanvasElement;\n /** Layers re-rendered through the magnified inner view in vector mode. */\n source: RenderLayer<unknown>[];\n requestRedraw: () => void;\n mode?: LoupeMode;\n factor?: number;\n bounds?: WidgetBounds;\n title?: string;\n /** Draw the window's titlebar and close box. Default `true`. Pass `false`\n * for a bare lens; the interior then doubles as the move handle. */\n titlebar?: boolean;\n /** Called with the hex color under the aim point whenever it changes.\n * Sampled from the framebuffer in both modes — vector content is a\n * re-render whose edge colors differ from the screen's, so reading the\n * color off it would report something the user cannot see. */\n onColorChange?: (hex: string) => void;\n /** Fired by the window's close box. The window does not hide itself —\n * whoever owns the loupe's visibility decides what closing means. */\n onClose?: () => void;\n /** Opaque backdrop behind vector content, so the outer canvas does not\n * show through where the inner view is empty. */\n background?: string;\n}\n\nexport interface LoupeHandle {\n readonly window: WindowWidget;\n readonly mode: LoupeMode;\n readonly factor: number;\n /** Last aimed point, in screen-space CSS px relative to the canvas. */\n readonly aim: { x: number; y: number };\n /** Hex color under the aim point, read off the framebuffer. `null` before\n * the first aim, or when the GL context is unavailable. */\n readonly color: string | null;\n setMode(mode: LoupeMode): void;\n setFactor(factor: number): void;\n /** Aim at a screen point. Ignored while the point is over the window —\n * that is the freeze rule that makes the borders reachable. */\n aimAt(p: { x: number; y: number }): void;\n dispose(): void;\n}\n\nexport function createLoupe(opts: LoupeOptions): LoupeHandle {\n const { hud, element, source, requestRedraw } = opts;\n let mode: LoupeMode = opts.mode ?? 'vector';\n let factor = opts.factor ?? 8;\n let aim = { x: 0, y: 0 };\n let color: string | null = null;\n let pixels: ImageBitmap | null = null;\n let pixelsPending = false;\n\n const b = opts.bounds ?? { x: 24, y: 24, w: 220, h: 200 };\n\n const content = (ctx: HudContentCtx): DrawCommand[] =>\n mode === 'vector' ? drawVector(ctx) : drawPixels(ctx);\n\n const drawVector = (ctx: HudContentCtx): DrawCommand[] => {\n const world = screenToWorld(aim.x, aim.y, viewToTransform(ctx.view));\n const inner: View = loupeInnerView(\n { x: world[0], y: world[1] }, ctx.view, ctx.rect, factor,\n );\n // A fresh lens per frame: CreateViewportLayerOpts.view is static, and the\n // inner view moves with the pointer.\n const lens = createViewportLayer<unknown>({\n id: `${win.id}:lens`,\n label: 'Loupe content',\n source,\n view: inner,\n bounds: () => ctx.rect,\n background: opts.background ?? ctx.tokens['--wzl-surface'],\n });\n return lens.draw(ctx.data, ctx.view, ctx.dims);\n };\n\n const drawPixels = (ctx: HudContentCtx): DrawCommand[] => {\n if (!pixels) return [];\n return [{\n kind: 'image',\n image: pixels,\n x: ctx.rect.x, y: ctx.rect.y, w: ctx.rect.w, h: ctx.rect.h,\n sampling: 'nearest',\n }];\n };\n\n const refreshPixels = () => {\n if (mode !== 'pixel' || pixelsPending) return;\n const gl = element.getContext('webgl2');\n if (!gl) return;\n const cssRect = element.getBoundingClientRect();\n if (cssRect.width === 0) return;\n const dpr = element.width / cssRect.width;\n const rect = win.contentRect;\n const rw = Math.max(1, Math.round((rect.w * dpr) / factor));\n const rh = Math.max(1, Math.round((rect.h * dpr) / factor));\n const data = readbackRegion(\n gl, { width: element.width, height: element.height }, aim, dpr, rw, rh,\n );\n pixelsPending = true;\n createImageBitmap(data)\n .then((bmp) => {\n pixels?.close();\n pixels = bmp;\n pixelsPending = false;\n requestRedraw();\n })\n .catch(() => { pixelsPending = false; });\n };\n\n const sampleColor = () => {\n const gl = element.getContext('webgl2');\n if (!gl) return;\n const cssRect = element.getBoundingClientRect();\n if (cssRect.width === 0) return;\n const dpr = element.width / cssRect.width;\n const px = readbackRegion(\n gl, { width: element.width, height: element.height }, aim, dpr, 1, 1,\n );\n const hex = '#' + [px.data[0], px.data[1], px.data[2]]\n .map((c) => c.toString(16).padStart(2, '0')).join('');\n if (hex !== color) {\n color = hex;\n opts.onColorChange?.(hex);\n }\n };\n\n const win = hud.window({\n id: 'weasel-loupe',\n x: b.x, y: b.y, w: b.w, h: b.h,\n title: opts.title ?? 'Loupe',\n titlebar: opts.titlebar,\n content,\n onResize: () => { refreshPixels(); },\n ...(opts.onClose ? { onClose: opts.onClose } : {}),\n });\n\n const onPointerMove = (evt: PointerEvent) => {\n const r = element.getBoundingClientRect();\n handleAim({ x: evt.clientX - r.left, y: evt.clientY - r.top });\n };\n\n const handleAim = (p: { x: number; y: number }) => {\n if (win.hidden) return;\n if (win.hitTest(p.x, p.y)) return; // freeze rule\n aim = p;\n sampleColor();\n if (mode === 'pixel') refreshPixels();\n requestRedraw();\n };\n\n element.addEventListener('pointermove', onPointerMove);\n\n return {\n window: win,\n get mode() { return mode; },\n get factor() { return factor; },\n get aim() { return aim; },\n get color() { return color; },\n setMode(next) {\n if (next === mode) return;\n mode = next;\n if (mode === 'pixel') refreshPixels();\n requestRedraw();\n },\n setFactor(next) {\n factor = next;\n if (mode === 'pixel') refreshPixels();\n requestRedraw();\n },\n aimAt: handleAim,\n dispose() {\n element.removeEventListener('pointermove', onPointerMove);\n pixels?.close();\n pixels = null;\n win.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/loupe/innerView.ts","../src/loupe/readback.ts","../src/loupe/createLoupe.ts"],"sourcesContent":["import type { View } from '@weasel-js/core';\nimport type { WidgetBounds } from '../widget';\n\n/**\n * The inner `View` a loupe renders its content through: the outer view's\n * magnification times `factor`, positioned so `target` sits at the center of\n * a viewport the size of `rect`.\n */\nexport function loupeInnerView(\n target: { x: number; y: number },\n outer: View,\n rect: WidgetBounds,\n factor: number,\n): View {\n const scale = { x: outer.scale.x * factor, y: outer.scale.y * factor };\n return {\n x: target.x - rect.w / 2 / scale.x,\n y: target.y - rect.h / 2 / scale.y,\n scale,\n };\n}\n","/**\n * Read a `rw × rh` device-pixel region of the drawing buffer centered on\n * `pointer` (CSS px relative to the canvas), returned top-down.\n *\n * GL reports rows bottom-up; every consumer here wants top-down, so both the\n * read origin and the returned rows are flipped.\n */\nexport function readbackRegion(\n gl: WebGL2RenderingContext,\n buffer: { width: number; height: number },\n pointer: { x: number; y: number },\n dpr: number,\n rw: number,\n rh: number,\n): ImageData {\n const cx = Math.round(pointer.x * dpr);\n const cy = Math.round(pointer.y * dpr);\n const gx = clamp(cx - Math.floor(rw / 2), 0, Math.max(0, buffer.width - rw));\n const gyTop = clamp(cy - Math.floor(rh / 2), 0, Math.max(0, buffer.height - rh));\n const gy = buffer.height - gyTop - rh;\n\n const raw = new Uint8Array(rw * rh * 4);\n gl.readPixels(gx, gy, rw, rh, gl.RGBA, gl.UNSIGNED_BYTE, raw);\n\n const flipped = new Uint8ClampedArray(rw * rh * 4);\n const stride = rw * 4;\n for (let row = 0; row < rh; row++) {\n const src = (rh - 1 - row) * stride;\n flipped.set(raw.subarray(src, src + stride), row * stride);\n }\n return new ImageData(flipped, rw, rh);\n}\n\nfunction clamp(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v;\n}\n","import {\n createViewportLayer, screenToWorld, viewToTransform,\n type RenderLayer, type View,\n} from '@weasel-js/core';\nimport type { DrawCommand } from '@weasel-js/core/renderer';\nimport type { Hud } from '../hud';\nimport type { WindowWidget } from '../widgets/window/window';\nimport type { HudContentCtx, WidgetBounds } from '../widget';\nimport { loupeInnerView } from './innerView';\nimport { readbackRegion } from './readback';\n\nexport type LoupeMode = 'vector' | 'pixel';\n\nexport interface LoupeOptions {\n hud: Hud;\n /** The live canvas. Supplies the GL context for pixel mode and the pointer\n * feed for aiming. */\n element: HTMLCanvasElement;\n /** Layers re-rendered through the magnified inner view in vector mode. */\n source: RenderLayer<unknown>[];\n requestRedraw: () => void;\n mode?: LoupeMode;\n factor?: number;\n bounds?: WidgetBounds;\n title?: string;\n /** Draw the window's titlebar and close box. Default `true`. Pass `false`\n * for a bare lens; the interior then doubles as the move handle. */\n titlebar?: boolean;\n /** Called with the hex color under the aim point whenever it changes.\n * Sampled from the framebuffer in both modes — vector content is a\n * re-render whose edge colors differ from the screen's, so reading the\n * color off it would report something the user cannot see. */\n onColorChange?: (hex: string) => void;\n /** Fired by the window's close box. The window does not hide itself —\n * whoever owns the loupe's visibility decides what closing means. */\n onClose?: () => void;\n /** Opaque backdrop behind vector content, so the outer canvas does not\n * show through where the inner view is empty. */\n background?: string;\n}\n\nexport interface LoupeHandle {\n readonly window: WindowWidget;\n readonly mode: LoupeMode;\n readonly factor: number;\n /** Last aimed point, in screen-space CSS px relative to the canvas. */\n readonly aim: { x: number; y: number };\n /** Hex color under the aim point, read off the framebuffer. `null` before\n * the first aim, or when the GL context is unavailable. */\n readonly color: string | null;\n setMode(mode: LoupeMode): void;\n setFactor(factor: number): void;\n /** Aim at a screen point. Ignored while the point is over the window —\n * that is the freeze rule that makes the borders reachable. */\n aimAt(p: { x: number; y: number }): void;\n dispose(): void;\n}\n\nexport function createLoupe(opts: LoupeOptions): LoupeHandle {\n const { hud, element, source, requestRedraw } = opts;\n let mode: LoupeMode = opts.mode ?? 'vector';\n let factor = opts.factor ?? 8;\n let aim = { x: 0, y: 0 };\n let color: string | null = null;\n let pixels: ImageBitmap | null = null;\n let pixelsPending = false;\n let pixelsStale = false;\n let disposed = false;\n\n const b = opts.bounds ?? { x: 24, y: 24, w: 220, h: 200 };\n\n const content = (ctx: HudContentCtx): DrawCommand[] =>\n mode === 'vector' ? drawVector(ctx) : drawPixels(ctx);\n\n const drawVector = (ctx: HudContentCtx): DrawCommand[] => {\n const world = screenToWorld(aim.x, aim.y, viewToTransform(ctx.view));\n const inner: View = loupeInnerView(\n { x: world[0], y: world[1] }, ctx.view, ctx.rect, factor,\n );\n // A fresh lens per frame: CreateViewportLayerOpts.view is static, and the\n // inner view moves with the pointer.\n const lens = createViewportLayer<unknown>({\n id: `${win.id}:lens`,\n label: 'Loupe content',\n source,\n view: inner,\n bounds: () => ctx.rect,\n background: opts.background ?? ctx.tokens['--wzl-surface'],\n });\n return lens.draw(ctx.data, ctx.view, ctx.dims);\n };\n\n const drawPixels = (ctx: HudContentCtx): DrawCommand[] => {\n if (!pixels) return [];\n return [{\n kind: 'image',\n image: pixels,\n x: ctx.rect.x, y: ctx.rect.y, w: ctx.rect.w, h: ctx.rect.h,\n sampling: 'nearest',\n }];\n };\n\n const refreshPixels = () => {\n if (disposed || mode !== 'pixel') return;\n // A readback requested mid-flight is remembered rather than dropped: the\n // aim that arrives during a fast drag is the one the user ends on.\n if (pixelsPending) { pixelsStale = true; return; }\n const gl = element.getContext('webgl2');\n if (!gl) return;\n const cssRect = element.getBoundingClientRect();\n if (cssRect.width === 0) return;\n const dpr = element.width / cssRect.width;\n const rect = win.contentRect;\n const rw = Math.max(1, Math.round((rect.w * dpr) / factor));\n const rh = Math.max(1, Math.round((rect.h * dpr) / factor));\n const data = readbackRegion(\n gl, { width: element.width, height: element.height }, aim, dpr, rw, rh,\n );\n pixelsPending = true;\n pixelsStale = false;\n createImageBitmap(data)\n .then((bmp) => {\n if (disposed) { bmp.close(); return; }\n pixels?.close();\n pixels = bmp;\n pixelsPending = false;\n requestRedraw();\n if (pixelsStale) refreshPixels();\n })\n .catch(() => {\n pixelsPending = false;\n if (pixelsStale) refreshPixels();\n });\n };\n\n const sampleColor = () => {\n const gl = element.getContext('webgl2');\n if (!gl) return;\n const cssRect = element.getBoundingClientRect();\n if (cssRect.width === 0) return;\n const dpr = element.width / cssRect.width;\n const px = readbackRegion(\n gl, { width: element.width, height: element.height }, aim, dpr, 1, 1,\n );\n const hex = '#' + [px.data[0], px.data[1], px.data[2]]\n .map((c) => c.toString(16).padStart(2, '0')).join('');\n if (hex !== color) {\n color = hex;\n opts.onColorChange?.(hex);\n }\n };\n\n const win = hud.window({\n id: 'weasel-loupe',\n x: b.x, y: b.y, w: b.w, h: b.h,\n title: opts.title ?? 'Loupe',\n titlebar: opts.titlebar,\n content,\n onResize: () => { refreshPixels(); },\n ...(opts.onClose ? { onClose: opts.onClose } : {}),\n });\n\n const onPointerMove = (evt: PointerEvent) => {\n const r = element.getBoundingClientRect();\n handleAim({ x: evt.clientX - r.left, y: evt.clientY - r.top });\n };\n\n const handleAim = (p: { x: number; y: number }) => {\n if (win.hidden) return;\n if (win.hitTest(p.x, p.y)) return; // freeze rule\n aim = p;\n sampleColor();\n if (mode === 'pixel') refreshPixels();\n requestRedraw();\n };\n\n element.addEventListener('pointermove', onPointerMove);\n\n return {\n window: win,\n get mode() { return mode; },\n get factor() { return factor; },\n get aim() { return aim; },\n get color() { return color; },\n setMode(next) {\n if (next === mode) return;\n mode = next;\n if (mode === 'pixel') refreshPixels();\n requestRedraw();\n },\n setFactor(next) {\n factor = next;\n if (mode === 'pixel') refreshPixels();\n requestRedraw();\n },\n aimAt: handleAim,\n dispose() {\n disposed = true;\n element.removeEventListener('pointermove', onPointerMove);\n pixels?.close();\n pixels = null;\n win.dispose();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createLoupe.d.ts","sourceRoot":"","sources":["../../src/loupe/createLoupe.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,WAAW,CAAC;AAI7D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,GAAG,CAAC;IACT;2BACuB;IACvB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,0EAA0E;IAC1E,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;yEACqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;mEAG+D;IAC/D,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;0EACsE;IACtE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;sDACkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC;gEAC4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;oEACgE;IAChE,KAAK,CAAC,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"createLoupe.d.ts","sourceRoot":"","sources":["../../src/loupe/createLoupe.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,WAAW,CAAC;AAI7D,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,GAAG,CAAC;IACT;2BACuB;IACvB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,0EAA0E;IAC1E,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;yEACqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;mEAG+D;IAC/D,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;0EACsE;IACtE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;sDACkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,QAAQ,CAAC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC;gEAC4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;oEACgE;IAChE,KAAK,CAAC,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CAkJ3D"}
|
package/dist/react/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as e, n as t, r as n } from "../tool-
|
|
1
|
+
import { c as e, n as t, r as n } from "../tool-DyPy2h0T.js";
|
|
2
2
|
import { resolveTheme as r, weaselTheme as i } from "@weasel-js/theme";
|
|
3
3
|
import { useEffect as a, useMemo as o, useState as s } from "react";
|
|
4
4
|
import { useThemeOptional as c } from "@weasel-js/theme/react";
|
|
@@ -238,6 +238,9 @@ function d(e) {
|
|
|
238
238
|
hitTest(e, t) {
|
|
239
239
|
return i ? !1 : d(e, t);
|
|
240
240
|
},
|
|
241
|
+
cursorAt(t, n) {
|
|
242
|
+
return i || !d(t, n) ? "default" : e.cursor ?? "pointer";
|
|
243
|
+
},
|
|
241
244
|
onPointer(t) {
|
|
242
245
|
switch (t.type) {
|
|
243
246
|
case "down":
|
|
@@ -598,9 +601,12 @@ var C = [
|
|
|
598
601
|
function w(e) {
|
|
599
602
|
return e.claims ?? C;
|
|
600
603
|
}
|
|
604
|
+
function T(e, t, n) {
|
|
605
|
+
return e.cursorAt?.(t, n) ?? (w(e).includes("pointer") ? "pointer" : void 0);
|
|
606
|
+
}
|
|
601
607
|
//#endregion
|
|
602
608
|
//#region src/attach.ts
|
|
603
|
-
function
|
|
609
|
+
function E(e, t, i = {}) {
|
|
604
610
|
let s = i.theme ?? a(o, o.defaultMode);
|
|
605
611
|
if (t.attached) throw Error("weasel-hud: this HUD is already attached to a canvas.");
|
|
606
612
|
S().then(() => e.requestRedraw()).catch((e) => {
|
|
@@ -652,12 +658,14 @@ function T(e, t, i = {}) {
|
|
|
652
658
|
},
|
|
653
659
|
hitTest: (e, t, i, a, o) => {
|
|
654
660
|
let [s, c] = r(e, t, n(a)), u = l(s, c);
|
|
655
|
-
|
|
661
|
+
if (!u) return null;
|
|
662
|
+
let d = T(u, s, c);
|
|
663
|
+
return {
|
|
656
664
|
initialScratch: { widget: u },
|
|
657
665
|
strength: "exclusive",
|
|
658
666
|
claimedKinds: w(u),
|
|
659
|
-
...
|
|
660
|
-
}
|
|
667
|
+
...d === void 0 ? {} : { cursor: d }
|
|
668
|
+
};
|
|
661
669
|
},
|
|
662
670
|
onUncapturedMove: (t, i, a, o) => {
|
|
663
671
|
let [s, u] = r(t, i, n(o)), d = l(s, u);
|
|
@@ -687,30 +695,30 @@ function T(e, t, i = {}) {
|
|
|
687
695
|
}
|
|
688
696
|
//#endregion
|
|
689
697
|
//#region src/tool.ts
|
|
690
|
-
var
|
|
698
|
+
var D = "layer:weasel-hud", O = {
|
|
691
699
|
shift: "optional",
|
|
692
700
|
alt: "optional",
|
|
693
701
|
meta: "optional",
|
|
694
702
|
ctrl: "optional"
|
|
695
703
|
};
|
|
696
|
-
function O(e) {
|
|
697
|
-
return e?.kind === E;
|
|
698
|
-
}
|
|
699
704
|
function k(e) {
|
|
700
|
-
return e?.
|
|
705
|
+
return e?.kind === D;
|
|
701
706
|
}
|
|
702
707
|
function A(e) {
|
|
708
|
+
return e?.payload?.widget ?? null;
|
|
709
|
+
}
|
|
710
|
+
function j(e) {
|
|
703
711
|
return Object.assign((t) => {
|
|
704
|
-
if (!
|
|
705
|
-
let n =
|
|
712
|
+
if (!k(t)) return !1;
|
|
713
|
+
let n = A(t);
|
|
706
714
|
return n !== null && w(n).includes(e);
|
|
707
715
|
}, { readsAffordance: !0 });
|
|
708
716
|
}
|
|
709
|
-
function
|
|
717
|
+
function M(e, t, i) {
|
|
710
718
|
let a = e.view?.get();
|
|
711
719
|
return a ? r(t, i, n(a)) : [t, i];
|
|
712
720
|
}
|
|
713
|
-
function
|
|
721
|
+
function N() {
|
|
714
722
|
return {
|
|
715
723
|
id: "hud.press",
|
|
716
724
|
label: "HUD — press widget",
|
|
@@ -718,9 +726,9 @@ function M() {
|
|
|
718
726
|
invoker: {
|
|
719
727
|
timing: "immediate",
|
|
720
728
|
run: (e, t) => {
|
|
721
|
-
let n = t, r =
|
|
729
|
+
let n = t, r = A(n?.affordance);
|
|
722
730
|
if (!r || n?.worldX === void 0 || n.worldY === void 0) return;
|
|
723
|
-
let [i, a] =
|
|
731
|
+
let [i, a] = M(e, n.worldX, n.worldY);
|
|
724
732
|
r.onPointer({
|
|
725
733
|
type: "down",
|
|
726
734
|
x: i,
|
|
@@ -731,7 +739,7 @@ function M() {
|
|
|
731
739
|
}
|
|
732
740
|
};
|
|
733
741
|
}
|
|
734
|
-
function
|
|
742
|
+
function P() {
|
|
735
743
|
return {
|
|
736
744
|
id: "hud.release",
|
|
737
745
|
label: "HUD — release widget",
|
|
@@ -739,9 +747,9 @@ function N() {
|
|
|
739
747
|
invoker: {
|
|
740
748
|
timing: "immediate",
|
|
741
749
|
run: (e, t) => {
|
|
742
|
-
let n = t, r =
|
|
750
|
+
let n = t, r = A(n?.affordance);
|
|
743
751
|
if (!r || n?.worldX === void 0 || n.worldY === void 0) return;
|
|
744
|
-
let [i, a] =
|
|
752
|
+
let [i, a] = M(e, n.worldX, n.worldY);
|
|
745
753
|
r.onPointer({
|
|
746
754
|
type: "up",
|
|
747
755
|
x: i,
|
|
@@ -752,7 +760,7 @@ function N() {
|
|
|
752
760
|
}
|
|
753
761
|
};
|
|
754
762
|
}
|
|
755
|
-
function
|
|
763
|
+
function F() {
|
|
756
764
|
return {
|
|
757
765
|
id: "hud.drag",
|
|
758
766
|
label: "HUD — drag widget",
|
|
@@ -760,12 +768,12 @@ function P() {
|
|
|
760
768
|
invoker: {
|
|
761
769
|
timing: "ongoing",
|
|
762
770
|
start: (e) => {
|
|
763
|
-
let t =
|
|
771
|
+
let t = A(e.drag?.affordance);
|
|
764
772
|
if (!t) return {};
|
|
765
773
|
let n = e.deps;
|
|
766
774
|
return {
|
|
767
775
|
onMove: (e) => {
|
|
768
|
-
let [r, i] =
|
|
776
|
+
let [r, i] = M(n, e.world.x, e.world.y);
|
|
769
777
|
t.onPointer({
|
|
770
778
|
type: "move",
|
|
771
779
|
x: r,
|
|
@@ -781,7 +789,7 @@ function P() {
|
|
|
781
789
|
});
|
|
782
790
|
return;
|
|
783
791
|
}
|
|
784
|
-
let [i, a] =
|
|
792
|
+
let [i, a] = M(n, e.world.x, e.world.y);
|
|
785
793
|
t.onPointer({
|
|
786
794
|
type: "up",
|
|
787
795
|
x: i,
|
|
@@ -794,7 +802,7 @@ function P() {
|
|
|
794
802
|
}
|
|
795
803
|
};
|
|
796
804
|
}
|
|
797
|
-
function
|
|
805
|
+
function I(e, t, n) {
|
|
798
806
|
return {
|
|
799
807
|
id: e,
|
|
800
808
|
label: t,
|
|
@@ -802,9 +810,9 @@ function F(e, t, n) {
|
|
|
802
810
|
invoker: {
|
|
803
811
|
timing: "immediate",
|
|
804
812
|
run: (e, t) => {
|
|
805
|
-
let r = t, i =
|
|
813
|
+
let r = t, i = A(r?.affordance);
|
|
806
814
|
if (!i || r?.worldX === void 0 || r.worldY === void 0) return;
|
|
807
|
-
let [a, o] =
|
|
815
|
+
let [a, o] = M(e, r.worldX, r.worldY);
|
|
808
816
|
i.onPointer({
|
|
809
817
|
type: n,
|
|
810
818
|
x: a,
|
|
@@ -815,14 +823,14 @@ function F(e, t, n) {
|
|
|
815
823
|
}
|
|
816
824
|
};
|
|
817
825
|
}
|
|
818
|
-
function
|
|
826
|
+
function L() {
|
|
819
827
|
return {
|
|
820
828
|
id: "hud.wheel",
|
|
821
829
|
label: "HUD — wheel over widget",
|
|
822
830
|
invoker: {
|
|
823
831
|
timing: "immediate",
|
|
824
832
|
run: (e, t) => {
|
|
825
|
-
let n = t, r =
|
|
833
|
+
let n = t, r = A(n?.affordance);
|
|
826
834
|
!r || n?.clientX === void 0 || n.clientY === void 0 || r.onPointer({
|
|
827
835
|
type: "wheel",
|
|
828
836
|
x: n.clientX,
|
|
@@ -835,73 +843,73 @@ function I() {
|
|
|
835
843
|
}
|
|
836
844
|
};
|
|
837
845
|
}
|
|
838
|
-
function
|
|
846
|
+
function R() {
|
|
839
847
|
return {
|
|
840
848
|
id: "weasel-hud",
|
|
841
849
|
eligibility: { claimed: !0 },
|
|
842
850
|
actions: [
|
|
843
|
-
M(),
|
|
844
851
|
N(),
|
|
845
852
|
P(),
|
|
846
|
-
F(
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
I()
|
|
853
|
+
F(),
|
|
854
|
+
I("hud.doubleClick", "HUD — double-click widget", "doubleclick"),
|
|
855
|
+
I("hud.contextMenu", "HUD — right-click widget", "contextmenu"),
|
|
856
|
+
I("hud.longPress", "HUD — long-press widget", "longpress"),
|
|
857
|
+
L()
|
|
850
858
|
],
|
|
851
859
|
bindings: [
|
|
852
860
|
{
|
|
853
861
|
spec: {
|
|
854
862
|
kind: "pointerDown",
|
|
855
|
-
target: { kindOf:
|
|
856
|
-
mods:
|
|
863
|
+
target: { kindOf: j("pointer") },
|
|
864
|
+
mods: O
|
|
857
865
|
},
|
|
858
866
|
actionId: "hud.press"
|
|
859
867
|
},
|
|
860
868
|
{
|
|
861
869
|
spec: {
|
|
862
870
|
kind: "click",
|
|
863
|
-
target: { kindOf:
|
|
864
|
-
mods:
|
|
871
|
+
target: { kindOf: j("pointer") },
|
|
872
|
+
mods: O
|
|
865
873
|
},
|
|
866
874
|
actionId: "hud.release"
|
|
867
875
|
},
|
|
868
876
|
{
|
|
869
877
|
spec: {
|
|
870
878
|
kind: "drag",
|
|
871
|
-
target: { kindOf:
|
|
872
|
-
mods:
|
|
879
|
+
target: { kindOf: j("pointer") },
|
|
880
|
+
mods: O
|
|
873
881
|
},
|
|
874
882
|
actionId: "hud.drag"
|
|
875
883
|
},
|
|
876
884
|
{
|
|
877
885
|
spec: {
|
|
878
886
|
kind: "doubleClick",
|
|
879
|
-
target: { kindOf:
|
|
880
|
-
mods:
|
|
887
|
+
target: { kindOf: j("doubleClick") },
|
|
888
|
+
mods: O
|
|
881
889
|
},
|
|
882
890
|
actionId: "hud.doubleClick"
|
|
883
891
|
},
|
|
884
892
|
{
|
|
885
893
|
spec: {
|
|
886
894
|
kind: "contextMenu",
|
|
887
|
-
target: { kindOf:
|
|
888
|
-
mods:
|
|
895
|
+
target: { kindOf: j("contextMenu") },
|
|
896
|
+
mods: O
|
|
889
897
|
},
|
|
890
898
|
actionId: "hud.contextMenu"
|
|
891
899
|
},
|
|
892
900
|
{
|
|
893
901
|
spec: {
|
|
894
902
|
kind: "longPress",
|
|
895
|
-
target: { kindOf:
|
|
896
|
-
mods:
|
|
903
|
+
target: { kindOf: j("longPress") },
|
|
904
|
+
mods: O
|
|
897
905
|
},
|
|
898
906
|
actionId: "hud.longPress"
|
|
899
907
|
},
|
|
900
908
|
{
|
|
901
909
|
spec: {
|
|
902
910
|
kind: "wheel",
|
|
903
|
-
target: { kindOf:
|
|
904
|
-
mods:
|
|
911
|
+
target: { kindOf: j("wheel") },
|
|
912
|
+
mods: O
|
|
905
913
|
},
|
|
906
914
|
actionId: "hud.wheel"
|
|
907
915
|
}
|
|
@@ -909,6 +917,6 @@ function L() {
|
|
|
909
917
|
};
|
|
910
918
|
}
|
|
911
919
|
//#endregion
|
|
912
|
-
export { w as a, v as c, C as i, f as l,
|
|
920
|
+
export { w as a, v as c, C as i, f as l, R as n, x as o, E as r, S as s, D as t, g as u };
|
|
913
921
|
|
|
914
|
-
//# sourceMappingURL=tool-
|
|
922
|
+
//# sourceMappingURL=tool-DyPy2h0T.js.map
|