@proto-labs-inc/rig-core 0.1.0 → 0.2.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/dist/frame-tools-loader.d.ts +2 -0
- package/dist/frame-tools-loader.js +47 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -337
- package/package.json +2 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Stable bootstrap only. Selection behavior is deployed with the Frame app. */
|
|
2
|
+
export function loadFrameTools(frameOrigin) {
|
|
3
|
+
if (window.parent === window)
|
|
4
|
+
return () => { };
|
|
5
|
+
let disposed = false;
|
|
6
|
+
let unmount;
|
|
7
|
+
const report = (status, origin = "*") => {
|
|
8
|
+
if (!disposed)
|
|
9
|
+
window.parent.postMessage({ type: "frame-tools-status", status }, origin);
|
|
10
|
+
};
|
|
11
|
+
const dispose = () => { disposed = true; unmount?.(); };
|
|
12
|
+
if (!frameOrigin) {
|
|
13
|
+
report("unavailable");
|
|
14
|
+
return dispose;
|
|
15
|
+
}
|
|
16
|
+
let origin;
|
|
17
|
+
try {
|
|
18
|
+
const url = new URL(frameOrigin);
|
|
19
|
+
const local = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
|
|
20
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && local))
|
|
21
|
+
throw new Error("Invalid Frame origin");
|
|
22
|
+
if (url.username || url.password || url.origin !== frameOrigin)
|
|
23
|
+
throw new Error("Expected an origin");
|
|
24
|
+
origin = url.origin;
|
|
25
|
+
// The origin is pinned in the prototype, never taken from a message or URL parameter.
|
|
26
|
+
if (!document.referrer || new URL(document.referrer).origin !== origin)
|
|
27
|
+
return dispose;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
report("unavailable");
|
|
31
|
+
return dispose;
|
|
32
|
+
}
|
|
33
|
+
report("loading", origin);
|
|
34
|
+
const url = new URL("/frame-tools/v1.js", origin).href;
|
|
35
|
+
void import(/* @vite-ignore */ url).then((runtime) => {
|
|
36
|
+
if (disposed)
|
|
37
|
+
return;
|
|
38
|
+
unmount = runtime.mountFrameTools({ frameOrigin: origin });
|
|
39
|
+
report("ready", origin);
|
|
40
|
+
}).catch((error) => {
|
|
41
|
+
if (disposed)
|
|
42
|
+
return;
|
|
43
|
+
console.warn("Proto selection tools failed to load", error);
|
|
44
|
+
report("unavailable", origin);
|
|
45
|
+
});
|
|
46
|
+
return dispose;
|
|
47
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The rig's framework-free core: URL-state sync, the bridge, and
|
|
3
|
-
*
|
|
2
|
+
* The rig's framework-free core: URL-state sync, the bridge, and the Frame tools
|
|
3
|
+
* loader. Everything here is plain DOM + history + postMessage — no framework.
|
|
4
4
|
* Framework adapters (@proto-labs-inc/rig for React, @proto-labs-inc/rig-vue for Vue) wrap
|
|
5
5
|
* this with their own idioms and nothing else.
|
|
6
6
|
*/
|
|
@@ -10,6 +10,7 @@ export declare const INTERNAL_PREVIEW_THEME_PARAM = "__protoTheme";
|
|
|
10
10
|
export declare function applyPreviewTheme(theme: ResolvedPreviewTheme): void;
|
|
11
11
|
/** All addressable state, mirrored to the URL. Keys: "state" | "v.<component>". */
|
|
12
12
|
export declare class RigStore {
|
|
13
|
+
private manifest;
|
|
13
14
|
private values;
|
|
14
15
|
private listeners;
|
|
15
16
|
constructor(manifest: Manifest);
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The rig's framework-free core: URL-state sync, the bridge, and
|
|
3
|
-
*
|
|
2
|
+
* The rig's framework-free core: URL-state sync, the bridge, and the Frame tools
|
|
3
|
+
* loader. Everything here is plain DOM + history + postMessage — no framework.
|
|
4
4
|
* Framework adapters (@proto-labs-inc/rig for React, @proto-labs-inc/rig-vue for Vue) wrap
|
|
5
5
|
* this with their own idioms and nothing else.
|
|
6
6
|
*/
|
|
7
|
-
import { PROTOCOL_VERSION, STATE_PARAM, variantParam, isFrameToRig, } from "@proto-labs-inc/wire";
|
|
7
|
+
import { PROTOCOL_VERSION, STATE_PARAM, variantParam, applyVariantSelection, isFrameToRig, } from "@proto-labs-inc/wire";
|
|
8
|
+
import { loadFrameTools } from "./frame-tools-loader.js";
|
|
8
9
|
export { STATE_PARAM, variantParam } from "@proto-labs-inc/wire";
|
|
9
|
-
const RIG_VERSION = "0.
|
|
10
|
+
const RIG_VERSION = "0.2.0";
|
|
10
11
|
export const INTERNAL_PREVIEW_THEME_PARAM = "__protoTheme";
|
|
11
12
|
export function applyPreviewTheme(theme) {
|
|
12
13
|
if (typeof document === "undefined")
|
|
@@ -29,9 +30,11 @@ function searchForFrame() {
|
|
|
29
30
|
}
|
|
30
31
|
/** All addressable state, mirrored to the URL. Keys: "state" | "v.<component>". */
|
|
31
32
|
export class RigStore {
|
|
33
|
+
manifest;
|
|
32
34
|
values = new Map();
|
|
33
35
|
listeners = new Set();
|
|
34
36
|
constructor(manifest) {
|
|
37
|
+
this.manifest = manifest;
|
|
35
38
|
if (typeof window === "undefined")
|
|
36
39
|
return;
|
|
37
40
|
const params = new URLSearchParams(window.location.search);
|
|
@@ -61,6 +64,13 @@ export class RigStore {
|
|
|
61
64
|
return this.values.get(key);
|
|
62
65
|
}
|
|
63
66
|
set(key, value) {
|
|
67
|
+
if (key.startsWith("v.")) {
|
|
68
|
+
const params = new URLSearchParams([...this.values]);
|
|
69
|
+
if (!applyVariantSelection(this.manifest.variantSets, params, key.slice(2), value))
|
|
70
|
+
return;
|
|
71
|
+
this.setMany([...params.entries()]);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
64
74
|
this.setMany([[key, value]]);
|
|
65
75
|
}
|
|
66
76
|
setMany(entries) {
|
|
@@ -121,48 +131,6 @@ export function postToFrame(msg) {
|
|
|
121
131
|
if (typeof window !== "undefined" && window.parent !== window)
|
|
122
132
|
window.parent.postMessage(msg, "*");
|
|
123
133
|
}
|
|
124
|
-
// ─── comment mode ──────────────────────────────────────────────────
|
|
125
|
-
// The Frame can't touch this document (cross-origin iframe), so the blue
|
|
126
|
-
// selector runs here: hit-test [data-proto-id] under the cursor, draw the
|
|
127
|
-
// highlight, and on click capture the view with the highlight baked in.
|
|
128
|
-
// The highlight is Proto blue (#0088FF): 2px solid at 55%, a 6% fill,
|
|
129
|
-
// radius 4px, 0.12s ease-out entry; the picker layer sits at z-index 99997.
|
|
130
|
-
const COMMENT_BLUE = "#0088FF";
|
|
131
|
-
const TARGET_ATTR = "data-proto-id";
|
|
132
|
-
function selectorFor(element) {
|
|
133
|
-
if (element === document.documentElement)
|
|
134
|
-
return "html";
|
|
135
|
-
if (element === document.body)
|
|
136
|
-
return "body";
|
|
137
|
-
const protoId = element.getAttribute(TARGET_ATTR);
|
|
138
|
-
if (protoId)
|
|
139
|
-
return `[${TARGET_ATTR}="${CSS.escape(protoId)}"]`;
|
|
140
|
-
if (element.id) {
|
|
141
|
-
const idSelector = `#${CSS.escape(element.id)}`;
|
|
142
|
-
if (document.querySelectorAll(idSelector).length === 1)
|
|
143
|
-
return idSelector;
|
|
144
|
-
}
|
|
145
|
-
const owner = element.closest(`[${TARGET_ATTR}]`);
|
|
146
|
-
const boundary = owner ?? document.body;
|
|
147
|
-
const segments = [];
|
|
148
|
-
let current = element;
|
|
149
|
-
while (current && current !== boundary) {
|
|
150
|
-
const tag = current.tagName.toLowerCase();
|
|
151
|
-
const currentTagName = current.tagName;
|
|
152
|
-
const siblings = current.parentElement
|
|
153
|
-
? [...current.parentElement.children].filter((sibling) => sibling.tagName === currentTagName)
|
|
154
|
-
: [];
|
|
155
|
-
const index = siblings.indexOf(current);
|
|
156
|
-
segments.unshift(siblings.length > 1 && index >= 0 ? `${tag}:nth-of-type(${index + 1})` : tag);
|
|
157
|
-
current = current.parentElement;
|
|
158
|
-
}
|
|
159
|
-
const base = owner
|
|
160
|
-
? `[${TARGET_ATTR}="${CSS.escape(owner.getAttribute(TARGET_ATTR) ?? "")}"]`
|
|
161
|
-
: boundary === element
|
|
162
|
-
? element.tagName.toLowerCase()
|
|
163
|
-
: "body";
|
|
164
|
-
return segments.length > 0 ? `${base} > ${segments.join(" > ")}` : base;
|
|
165
|
-
}
|
|
166
134
|
async function waitForCaptureReady() {
|
|
167
135
|
const pendingImages = [...document.images]
|
|
168
136
|
.filter((image) => !image.complete)
|
|
@@ -180,47 +148,6 @@ async function waitForCaptureReady() {
|
|
|
180
148
|
// resting state before the gallery captures them.
|
|
181
149
|
await new Promise((resolve) => window.setTimeout(resolve, 1500));
|
|
182
150
|
}
|
|
183
|
-
async function captureViewport(scale = Math.min(window.devicePixelRatio || 1, 2)) {
|
|
184
|
-
try {
|
|
185
|
-
// Optional peer provided by the prototype, not the rig.
|
|
186
|
-
const mod = (await import("modern-screenshot"));
|
|
187
|
-
const root = document.body;
|
|
188
|
-
const viewportWidth = document.documentElement.clientWidth;
|
|
189
|
-
const viewportHeight = document.documentElement.clientHeight;
|
|
190
|
-
const scrollX = window.scrollX || document.documentElement.scrollLeft;
|
|
191
|
-
const scrollY = window.scrollY || document.documentElement.scrollTop;
|
|
192
|
-
const contentWidth = Math.max(viewportWidth, document.documentElement.scrollWidth, root.scrollWidth);
|
|
193
|
-
const contentHeight = Math.max(viewportHeight, document.documentElement.scrollHeight, root.scrollHeight);
|
|
194
|
-
return await mod.domToDataUrl(root, {
|
|
195
|
-
scale,
|
|
196
|
-
width: viewportWidth,
|
|
197
|
-
height: viewportHeight,
|
|
198
|
-
features: { restoreScrollPosition: true },
|
|
199
|
-
style: {
|
|
200
|
-
margin: "0",
|
|
201
|
-
width: `${contentWidth}px`,
|
|
202
|
-
height: `${contentHeight}px`,
|
|
203
|
-
transform: `translate(${-scrollX}px, ${-scrollY}px)`,
|
|
204
|
-
transformOrigin: "top left",
|
|
205
|
-
overflow: "visible",
|
|
206
|
-
},
|
|
207
|
-
onCloneNode: (cloned) => {
|
|
208
|
-
if (!(cloned instanceof HTMLElement) || (!scrollX && !scrollY))
|
|
209
|
-
return;
|
|
210
|
-
const fixed = [cloned, ...cloned.querySelectorAll("*")].filter((element) => element.style.position === "fixed");
|
|
211
|
-
for (const element of fixed) {
|
|
212
|
-
const existing = element.style.transform;
|
|
213
|
-
element.style.transform =
|
|
214
|
-
`translate(${scrollX}px, ${scrollY}px)` +
|
|
215
|
-
(existing && existing !== "none" ? ` ${existing}` : "");
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
catch {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
151
|
async function captureThumbnail() {
|
|
225
152
|
const restingState = document.createElement("style");
|
|
226
153
|
restingState.textContent = `
|
|
@@ -267,225 +194,13 @@ async function captureThumbnail() {
|
|
|
267
194
|
restingState.remove();
|
|
268
195
|
}
|
|
269
196
|
}
|
|
270
|
-
class ElementPicker {
|
|
271
|
-
overlay = null;
|
|
272
|
-
highlight = null;
|
|
273
|
-
cursorStyle = null;
|
|
274
|
-
target = null;
|
|
275
|
-
active = false;
|
|
276
|
-
mode = null;
|
|
277
|
-
enable(mode) {
|
|
278
|
-
if (typeof document === "undefined")
|
|
279
|
-
return;
|
|
280
|
-
if (this.active || this.overlay)
|
|
281
|
-
this.disable();
|
|
282
|
-
this.active = true;
|
|
283
|
-
this.mode = mode;
|
|
284
|
-
this.cursorStyle = document.createElement("style");
|
|
285
|
-
this.cursorStyle.setAttribute("data-proto-picker-cursor", "");
|
|
286
|
-
this.cursorStyle.textContent =
|
|
287
|
-
"html, body, body * { cursor: crosshair !important; }";
|
|
288
|
-
document.head.appendChild(this.cursorStyle);
|
|
289
|
-
const blue = COMMENT_BLUE;
|
|
290
|
-
this.overlay = document.createElement("div");
|
|
291
|
-
this.overlay.setAttribute("data-proto-rig-overlay", "");
|
|
292
|
-
Object.assign(this.overlay.style, {
|
|
293
|
-
position: "fixed",
|
|
294
|
-
inset: "0",
|
|
295
|
-
zIndex: "99997",
|
|
296
|
-
pointerEvents: "none",
|
|
297
|
-
});
|
|
298
|
-
this.highlight = document.createElement("div");
|
|
299
|
-
Object.assign(this.highlight.style, {
|
|
300
|
-
position: "absolute",
|
|
301
|
-
border: `2px solid color-mix(in srgb, ${blue} 55%, transparent)`,
|
|
302
|
-
borderRadius: "4px",
|
|
303
|
-
backgroundColor: `color-mix(in srgb, ${blue} 6%, transparent)`,
|
|
304
|
-
pointerEvents: "none",
|
|
305
|
-
boxSizing: "border-box",
|
|
306
|
-
opacity: "0",
|
|
307
|
-
transition: "opacity 0.12s ease-out",
|
|
308
|
-
willChange: "opacity",
|
|
309
|
-
});
|
|
310
|
-
this.overlay.appendChild(this.highlight);
|
|
311
|
-
document.body.appendChild(this.overlay);
|
|
312
|
-
document.addEventListener("pointermove", this.onMove, true);
|
|
313
|
-
document.addEventListener("click", this.onClick, true);
|
|
314
|
-
document.addEventListener("keydown", this.onKey, true);
|
|
315
|
-
}
|
|
316
|
-
disable() {
|
|
317
|
-
if (!this.active && !this.overlay && !this.cursorStyle)
|
|
318
|
-
return;
|
|
319
|
-
this.active = false;
|
|
320
|
-
document.removeEventListener("pointermove", this.onMove, true);
|
|
321
|
-
document.removeEventListener("click", this.onClick, true);
|
|
322
|
-
document.removeEventListener("keydown", this.onKey, true);
|
|
323
|
-
this.overlay?.remove();
|
|
324
|
-
this.cursorStyle?.remove();
|
|
325
|
-
this.overlay = null;
|
|
326
|
-
this.highlight = null;
|
|
327
|
-
this.cursorStyle = null;
|
|
328
|
-
this.target = null;
|
|
329
|
-
this.mode = null;
|
|
330
|
-
}
|
|
331
|
-
freezeSelection() {
|
|
332
|
-
this.active = false;
|
|
333
|
-
document.removeEventListener("pointermove", this.onMove, true);
|
|
334
|
-
document.removeEventListener("click", this.onClick, true);
|
|
335
|
-
document.removeEventListener("keydown", this.onKey, true);
|
|
336
|
-
this.cursorStyle?.remove();
|
|
337
|
-
this.cursorStyle = null;
|
|
338
|
-
}
|
|
339
|
-
onMove = (e) => {
|
|
340
|
-
const hit = this.targetAt(e.clientX, e.clientY);
|
|
341
|
-
if (hit === this.target)
|
|
342
|
-
return;
|
|
343
|
-
this.target = hit;
|
|
344
|
-
if (!this.highlight)
|
|
345
|
-
return;
|
|
346
|
-
const rect = this.rectFor(hit);
|
|
347
|
-
Object.assign(this.highlight.style, {
|
|
348
|
-
left: `${rect.left}px`,
|
|
349
|
-
top: `${rect.top}px`,
|
|
350
|
-
width: `${rect.width}px`,
|
|
351
|
-
height: `${rect.height}px`,
|
|
352
|
-
opacity: "1",
|
|
353
|
-
});
|
|
354
|
-
};
|
|
355
|
-
onClick = (e) => {
|
|
356
|
-
e.preventDefault();
|
|
357
|
-
e.stopPropagation();
|
|
358
|
-
const clickedTarget = this.targetAt(e.clientX, e.clientY);
|
|
359
|
-
this.target = clickedTarget;
|
|
360
|
-
const targetId = clickedTarget?.getAttribute(TARGET_ATTR) ?? null;
|
|
361
|
-
if (this.mode === "element") {
|
|
362
|
-
const rect = this.rectFor(clickedTarget);
|
|
363
|
-
const text = clickedTarget.textContent?.replace(/\s+/g, " ").trim() || null;
|
|
364
|
-
this.disable();
|
|
365
|
-
postToFrame({
|
|
366
|
-
type: "element-target-picked",
|
|
367
|
-
selector: selectorFor(clickedTarget),
|
|
368
|
-
tagName: clickedTarget.tagName.toLowerCase(),
|
|
369
|
-
text: text?.slice(0, 160) ?? null,
|
|
370
|
-
anchor: {
|
|
371
|
-
x: rect.left,
|
|
372
|
-
y: rect.top,
|
|
373
|
-
width: rect.width,
|
|
374
|
-
height: rect.height,
|
|
375
|
-
},
|
|
376
|
-
});
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
if (this.mode === "variantSet") {
|
|
380
|
-
if (!targetId)
|
|
381
|
-
return;
|
|
382
|
-
const rect = this.rectFor(clickedTarget);
|
|
383
|
-
this.disable();
|
|
384
|
-
postToFrame({
|
|
385
|
-
type: "variant-set-target-picked",
|
|
386
|
-
targetId,
|
|
387
|
-
anchor: {
|
|
388
|
-
x: rect.left,
|
|
389
|
-
y: rect.top,
|
|
390
|
-
width: rect.width,
|
|
391
|
-
height: rect.height,
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
const rect = this.rectFor(clickedTarget);
|
|
397
|
-
if (this.highlight) {
|
|
398
|
-
Object.assign(this.highlight.style, {
|
|
399
|
-
left: `${rect.left}px`,
|
|
400
|
-
top: `${rect.top}px`,
|
|
401
|
-
width: `${rect.width}px`,
|
|
402
|
-
height: `${rect.height}px`,
|
|
403
|
-
opacity: "1",
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
this.freezeSelection();
|
|
407
|
-
postToFrame({
|
|
408
|
-
type: "comment-target-picked",
|
|
409
|
-
targetId,
|
|
410
|
-
anchor: {
|
|
411
|
-
x: rect.left,
|
|
412
|
-
y: rect.top,
|
|
413
|
-
width: rect.width,
|
|
414
|
-
height: rect.height,
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
};
|
|
418
|
-
targetAt(x, y) {
|
|
419
|
-
const hit = document.elementFromPoint(x, y);
|
|
420
|
-
if (this.mode === "element")
|
|
421
|
-
return hit ?? document.body;
|
|
422
|
-
return hit?.closest(`[${TARGET_ATTR}]`) ?? document.body;
|
|
423
|
-
}
|
|
424
|
-
rectFor(target) {
|
|
425
|
-
if (target === document.body || target === document.documentElement) {
|
|
426
|
-
return {
|
|
427
|
-
left: 0,
|
|
428
|
-
top: 0,
|
|
429
|
-
width: document.documentElement.clientWidth,
|
|
430
|
-
height: document.documentElement.clientHeight,
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
return target.getBoundingClientRect();
|
|
434
|
-
}
|
|
435
|
-
onKey = (e) => {
|
|
436
|
-
if (e.key !== "Escape")
|
|
437
|
-
return;
|
|
438
|
-
e.preventDefault();
|
|
439
|
-
const mode = this.mode;
|
|
440
|
-
this.disable();
|
|
441
|
-
postToFrame({
|
|
442
|
-
type: mode === "variantSet"
|
|
443
|
-
? "variant-set-picker-exited"
|
|
444
|
-
: mode === "element"
|
|
445
|
-
? "element-picker-exited"
|
|
446
|
-
: "comment-mode-exited",
|
|
447
|
-
});
|
|
448
|
-
};
|
|
449
|
-
async captureSelection(requestId) {
|
|
450
|
-
if (!this.target)
|
|
451
|
-
return;
|
|
452
|
-
const targetId = this.target.getAttribute(TARGET_ATTR);
|
|
453
|
-
const rect = this.rectFor(this.target);
|
|
454
|
-
const anchor = {
|
|
455
|
-
x: rect.left,
|
|
456
|
-
y: rect.top,
|
|
457
|
-
width: rect.width,
|
|
458
|
-
height: rect.height,
|
|
459
|
-
};
|
|
460
|
-
if (this.highlight) {
|
|
461
|
-
Object.assign(this.highlight.style, {
|
|
462
|
-
left: `${rect.left}px`,
|
|
463
|
-
top: `${rect.top}px`,
|
|
464
|
-
width: `${rect.width}px`,
|
|
465
|
-
height: `${rect.height}px`,
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
// The page is already interactive when the user picks a comment target.
|
|
469
|
-
// Capture immediately: thumbnail readiness delays can consume the Frame's
|
|
470
|
-
// request timeout on image-heavy prototypes.
|
|
471
|
-
const image = await captureViewport();
|
|
472
|
-
this.disable();
|
|
473
|
-
postToFrame({
|
|
474
|
-
type: "comment-capture",
|
|
475
|
-
targetId,
|
|
476
|
-
image,
|
|
477
|
-
requestId,
|
|
478
|
-
anchor,
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
const elementPicker = typeof window === "undefined" ? null : new ElementPicker();
|
|
483
197
|
/**
|
|
484
198
|
* Wire a store to the bridge: listen for Frame messages, announce the rig,
|
|
485
199
|
* and report the boot-time state (the deep-link fix). Returns a disposer.
|
|
486
200
|
* Call client-side only.
|
|
487
201
|
*/
|
|
488
202
|
export function wireRig(store, manifest) {
|
|
203
|
+
const disposeTools = loadFrameTools(manifest.frameOrigin);
|
|
489
204
|
let controlledTheme = false;
|
|
490
205
|
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
491
206
|
const onSystemTheme = () => {
|
|
@@ -494,6 +209,8 @@ export function wireRig(store, manifest) {
|
|
|
494
209
|
};
|
|
495
210
|
media.addEventListener("change", onSystemTheme);
|
|
496
211
|
const onMessage = (e) => {
|
|
212
|
+
if (e.source !== window.parent)
|
|
213
|
+
return;
|
|
497
214
|
if (!isFrameToRig(e.data))
|
|
498
215
|
return; // tolerate unknown messages silently
|
|
499
216
|
if (e.data.type === "set-state") {
|
|
@@ -506,42 +223,6 @@ export function wireRig(store, manifest) {
|
|
|
506
223
|
}
|
|
507
224
|
else if (e.data.type === "set-variant")
|
|
508
225
|
store.set(variantParam(e.data.component), e.data.variant);
|
|
509
|
-
else if (e.data.type === "measure-target") {
|
|
510
|
-
const target = Array.from(document.querySelectorAll(`[${TARGET_ATTR}]`)).find((candidate) => candidate.getAttribute(TARGET_ATTR) === e.data.id);
|
|
511
|
-
const rect = target?.getBoundingClientRect();
|
|
512
|
-
postToFrame({
|
|
513
|
-
type: "target-measured",
|
|
514
|
-
targetId: e.data.id,
|
|
515
|
-
anchor: rect
|
|
516
|
-
? {
|
|
517
|
-
x: rect.left,
|
|
518
|
-
y: rect.top,
|
|
519
|
-
width: rect.width,
|
|
520
|
-
height: rect.height,
|
|
521
|
-
}
|
|
522
|
-
: null,
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
else if (e.data.type === "set-comment-mode") {
|
|
526
|
-
if (e.data.on)
|
|
527
|
-
elementPicker?.enable("comment");
|
|
528
|
-
else
|
|
529
|
-
elementPicker?.disable();
|
|
530
|
-
}
|
|
531
|
-
else if (e.data.type === "capture-comment")
|
|
532
|
-
void elementPicker?.captureSelection(e.data.requestId);
|
|
533
|
-
else if (e.data.type === "set-variant-set-picker") {
|
|
534
|
-
if (e.data.on)
|
|
535
|
-
elementPicker?.enable("variantSet");
|
|
536
|
-
else
|
|
537
|
-
elementPicker?.disable();
|
|
538
|
-
}
|
|
539
|
-
else if (e.data.type === "set-element-picker") {
|
|
540
|
-
if (e.data.on)
|
|
541
|
-
elementPicker?.enable("element");
|
|
542
|
-
else
|
|
543
|
-
elementPicker?.disable();
|
|
544
|
-
}
|
|
545
226
|
};
|
|
546
227
|
window.addEventListener("message", onMessage);
|
|
547
228
|
postToFrame({
|
|
@@ -564,6 +245,6 @@ export function wireRig(store, manifest) {
|
|
|
564
245
|
return () => {
|
|
565
246
|
media.removeEventListener("change", onSystemTheme);
|
|
566
247
|
window.removeEventListener("message", onMessage);
|
|
567
|
-
|
|
248
|
+
disposeTools();
|
|
568
249
|
};
|
|
569
250
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proto-labs-inc/rig-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Proto's rig, framework-free: URL-state sync, the postMessage bridge to the Frame, and comment mode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@proto-labs-inc/wire": "^0.
|
|
31
|
+
"@proto-labs-inc/wire": "^0.2.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "~6.0.2",
|