@dorsk/yubisashi 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/README.md +77 -45
- package/dist/picker/index.d.ts +2 -0
- package/dist/picker/index.js +3 -0
- package/dist/picker/index.js.map +1 -0
- package/dist/picker/inspect.d.ts +5 -0
- package/dist/picker/inspect.js +87 -0
- package/dist/picker/inspect.js.map +1 -0
- package/dist/picker/picker.d.ts +29 -0
- package/dist/picker/picker.js +265 -0
- package/dist/picker/picker.js.map +1 -0
- package/dist/picker/protocol.d.ts +79 -0
- package/dist/picker/protocol.js +23 -0
- package/dist/picker/protocol.js.map +1 -0
- package/dist/vite/index.d.ts +15 -0
- package/dist/vite/index.js +150 -0
- package/dist/vite/index.js.map +1 -0
- package/package.json +60 -12
- package/shell/app.css +0 -436
- package/shell/app.js +0 -554
- package/shell/index.html +0 -46
- package/skill/SKILL.md +0 -50
- package/src/cli.ts +0 -259
- package/src/format.ts +0 -43
- package/src/proxy.ts +0 -89
- package/src/server.ts +0 -245
- package/src/store.ts +0 -113
- package/src/transcript.ts +0 -142
package/README.md
CHANGED
|
@@ -1,66 +1,98 @@
|
|
|
1
1
|
# yubisashi 指差し
|
|
2
2
|
|
|
3
|
-
Point at your running app
|
|
4
|
-
|
|
5
|
-
edits, and hot-reload shows you the result. The agent's conversation streams in a panel next to
|
|
6
|
-
the app.
|
|
3
|
+
Point at elements of your running app from a review panel and hand the coding agent the exact
|
|
4
|
+
source `file:line`, the component chain, the selector and your comment.
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
The review panel lives in [cctui](https://github.com/DorskFR/cctui) as the opt-in **yubisashi**
|
|
7
|
+
plugin. This package is the app side: a framework-free picker that runs inside the framed app,
|
|
8
|
+
and a Vite plugin that injects it in dev.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Use
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm install --save-dev @dorsk/yubisashi
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// vite.config.ts
|
|
18
|
+
import { yubisashi } from '@dorsk/yubisashi/vite';
|
|
11
19
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
plugins: [sveltekit(), yubisashi()],
|
|
22
|
+
});
|
|
23
|
+
```
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **Source location** comes from Svelte 5's dev-mode `__svelte_meta`, which gives exact
|
|
20
|
-
`file:line:col` plus the component chain. For other frameworks you still get the selector,
|
|
21
|
-
text and HTML.
|
|
22
|
-
- **Conversation tab**: follows the agent's Claude Code transcript live
|
|
23
|
-
(`~/.claude/projects/*/<session>.jsonl`).
|
|
24
|
-
- **Comments tab**: one thread per comment, with status and a pin on the element.
|
|
25
|
+
```sh
|
|
26
|
+
YUBI_PARENT_ORIGIN=https://cctui.example.com npm run dev
|
|
27
|
+
```
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
polling. The same works in any Claude Code session, including cctui ones.
|
|
29
|
+
Then in cctui: **Settings → Plugins → yubisashi**, open the **Review** pane and point it at the
|
|
30
|
+
dev server. Press `C` or the ⌖ button, click an element (shift-click adds more, `Esc` backs
|
|
31
|
+
out) and write the comment.
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
The plugin only runs under `vite dev` (`apply: 'serve'`) and does nothing at all unless
|
|
34
|
+
`YUBI_PARENT_ORIGIN` (comma-separated origins) or the `parentOrigin` option is set. When active,
|
|
35
|
+
it:
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
- injects `<script type="module" src="/@id/__x00__virtual:yubisashi">` into every HTML
|
|
38
|
+
response, which calls `createPicker({ parentOrigin })` only when the page is inside an iframe;
|
|
39
|
+
- drops `X-Frame-Options` and rewrites CSP `frame-ancestors` to the configured origins so the
|
|
40
|
+
panel may frame the app.
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
An `https` parent cannot frame a plain `http` page unless it is on `localhost`, so run the dev
|
|
43
|
+
server over https (`server.https`) when it lives anywhere else.
|
|
44
|
+
|
|
45
|
+
Source locations come from Svelte 5's dev-mode `__svelte_meta`. Other frameworks still get
|
|
46
|
+
selector, text, attributes and HTML.
|
|
47
|
+
|
|
48
|
+
## Picker on its own
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { createPicker } from '@dorsk/yubisashi/picker';
|
|
52
|
+
|
|
53
|
+
if (window.parent !== window)
|
|
54
|
+
createPicker({ parentOrigin: ['https://cctui.example.com', 'http://localhost:5555'] });
|
|
44
55
|
```
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
The picker talks to the parent window through `postMessage` only. It accepts messages solely
|
|
58
|
+
from `window.parent` at an allowed origin; with several origins it pins itself to the one that
|
|
59
|
+
frames the document (`ancestorOrigins` / `referrer`), otherwise to the first allowed origin
|
|
60
|
+
that sends a valid message.
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
automatically and holds the comments, the token and the server address.
|
|
62
|
+
## Protocol
|
|
51
63
|
|
|
52
|
-
|
|
64
|
+
Every message, both ways, carries `yubi: 1`; anything without it is ignored.
|
|
53
65
|
|
|
54
|
-
|
|
55
|
-
127.0.0.1 by default, and every API call needs the random token in `.yubisashi/token`, which
|
|
56
|
-
also stops other sites in your browser from posting to it. Think twice before `--host 0.0.0.0`.
|
|
66
|
+
Parent → app:
|
|
57
67
|
|
|
58
|
-
|
|
68
|
+
| type | fields |
|
|
69
|
+
| ------------ | -------------------------- |
|
|
70
|
+
| `pick:start` | |
|
|
71
|
+
| `pick:stop` | |
|
|
72
|
+
| `pick:clear` | `id?: number` (pin the selection to comment #id) |
|
|
73
|
+
| `pins:set` | `pins: { id, selector }[]` |
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
App → parent:
|
|
76
|
+
|
|
77
|
+
| type | fields |
|
|
78
|
+
| --------------- | ----------------------------------------------- |
|
|
79
|
+
| `route` | `route: string` |
|
|
80
|
+
| `pick:state` | `picking: boolean` |
|
|
81
|
+
| `pick:hover` | `target: Target \| null` |
|
|
82
|
+
| `pick:selected` | `targets: Target[]`, `route`, `viewport` |
|
|
83
|
+
| `pick:cancel` | |
|
|
84
|
+
| `pin:open` | `id: number` |
|
|
85
|
+
|
|
86
|
+
`Target`: `tag`, `selector`, `text`, `html`, `attrs`, `rect`, `source?: { file, line, column }`,
|
|
87
|
+
`stack: Frame[]` (the components that rendered it). Types and the `isParentMessage` /
|
|
88
|
+
`isChildMessage` guards are exported from `@dorsk/yubisashi/picker`.
|
|
89
|
+
|
|
90
|
+
## Develop
|
|
61
91
|
|
|
62
92
|
```sh
|
|
63
93
|
npm install
|
|
64
|
-
|
|
65
|
-
npm run
|
|
94
|
+
npx playwright install chromium
|
|
95
|
+
npm run lint # biome
|
|
96
|
+
npm run check # tsc
|
|
97
|
+
npm test # builds dist, then Playwright tests for the picker and the Vite plugin (plain Vite + SvelteKit)
|
|
66
98
|
```
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { describe, label, selectorOf } from './inspect.ts';
|
|
2
|
+
export { type ChildMessage, createPicker, type Frame, isChildMessage, isParentMessage, type ParentMessage, type PickerHandle, type PickerOptions, type Pin, type Target, type Unmarked, type Viewport, YUBI, } from './picker.ts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/picker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAEN,YAAY,EAEZ,cAAc,EACd,eAAe,EAQf,IAAI,GACJ,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Target } from './protocol.ts';
|
|
2
|
+
export declare const shortFile: (file?: string) => string;
|
|
3
|
+
export declare function selectorOf(el: Element): string;
|
|
4
|
+
export declare function describe(el: Element): Target;
|
|
5
|
+
export declare const label: (info: Target) => string;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const shortFile = (file) => (file ? (file.split('/').at(-1) ?? '') : '');
|
|
2
|
+
function svelteMeta(el) {
|
|
3
|
+
for (let node = el; node; node = node.parentElement) {
|
|
4
|
+
const meta = node.__svelte_meta;
|
|
5
|
+
if (meta)
|
|
6
|
+
return meta;
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
function stackOf(meta) {
|
|
11
|
+
const frames = [];
|
|
12
|
+
for (let p = meta?.parent; p && frames.length < 12; p = p.parent) {
|
|
13
|
+
if (p.type !== 'component' || p.file?.includes('.svelte-kit/generated'))
|
|
14
|
+
continue;
|
|
15
|
+
frames.push({
|
|
16
|
+
type: p.type,
|
|
17
|
+
name: p.componentTag ? `<${p.componentTag}>` : undefined,
|
|
18
|
+
file: p.file,
|
|
19
|
+
line: p.line,
|
|
20
|
+
column: p.column,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return frames;
|
|
24
|
+
}
|
|
25
|
+
const SCOPED_CLASS = /^(svelte|s)-[\w-]{5,}$/;
|
|
26
|
+
const HOOK_ATTRS = ['data-testid', 'data-verb', 'data-test'];
|
|
27
|
+
const KEPT_ATTRS = ['role', 'aria-label', 'href', 'name', 'type', 'title', 'alt'];
|
|
28
|
+
export function selectorOf(el) {
|
|
29
|
+
const doc = el.ownerDocument;
|
|
30
|
+
const parts = [];
|
|
31
|
+
for (let node = el; node && node.nodeType === 1 && node !== doc.documentElement; node = node.parentElement) {
|
|
32
|
+
for (const attr of HOOK_ATTRS) {
|
|
33
|
+
const value = node.getAttribute(attr);
|
|
34
|
+
if (value) {
|
|
35
|
+
parts.unshift(`[${attr}="${CSS.escape(value)}"]`);
|
|
36
|
+
return parts.join(' > ');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (node.id && !/\d{3,}/.test(node.id)) {
|
|
40
|
+
parts.unshift(`#${CSS.escape(node.id)}`);
|
|
41
|
+
return parts.join(' > ');
|
|
42
|
+
}
|
|
43
|
+
let part = node.localName;
|
|
44
|
+
const classes = [...node.classList].filter((c) => !SCOPED_CLASS.test(c)).slice(0, 2);
|
|
45
|
+
if (classes.length)
|
|
46
|
+
part += classes.map((c) => `.${CSS.escape(c)}`).join('');
|
|
47
|
+
const siblings = node.parentElement
|
|
48
|
+
? [...node.parentElement.children].filter((s) => s.localName === node.localName)
|
|
49
|
+
: [];
|
|
50
|
+
if (siblings.length > 1)
|
|
51
|
+
part += `:nth-of-type(${siblings.indexOf(node) + 1})`;
|
|
52
|
+
parts.unshift(part);
|
|
53
|
+
if (parts.length >= 6)
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
return parts.join(' > ');
|
|
57
|
+
}
|
|
58
|
+
export function describe(el) {
|
|
59
|
+
const meta = svelteMeta(el);
|
|
60
|
+
const attrs = {};
|
|
61
|
+
for (const a of el.attributes) {
|
|
62
|
+
if (a.name.startsWith('data-') || KEPT_ATTRS.includes(a.name))
|
|
63
|
+
attrs[a.name] = a.value.slice(0, 200);
|
|
64
|
+
}
|
|
65
|
+
const r = el.getBoundingClientRect();
|
|
66
|
+
const html = el.outerHTML.replace(/\s+/g, ' ');
|
|
67
|
+
const text = el.innerText ?? el.textContent ?? '';
|
|
68
|
+
return {
|
|
69
|
+
tag: el.localName,
|
|
70
|
+
selector: selectorOf(el),
|
|
71
|
+
text: text.replace(/\s+/g, ' ').trim().slice(0, 100),
|
|
72
|
+
html: html.length > 500 ? `${html.slice(0, 500)}…` : html,
|
|
73
|
+
attrs,
|
|
74
|
+
rect: {
|
|
75
|
+
x: Math.round(r.x),
|
|
76
|
+
y: Math.round(r.y),
|
|
77
|
+
width: Math.round(r.width),
|
|
78
|
+
height: Math.round(r.height),
|
|
79
|
+
},
|
|
80
|
+
source: meta
|
|
81
|
+
? { file: meta.loc.file, line: meta.loc.line, column: meta.loc.column ?? 0 }
|
|
82
|
+
: undefined,
|
|
83
|
+
stack: stackOf(meta),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export const label = (info) => `<${info.tag}> ${info.source ? `${shortFile(info.source.file)}:${info.source.line}` : info.selector}`;
|
|
87
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/picker/inspect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ChildMessage, type Frame, type ParentMessage, type Pin, type Target, type Unmarked, type Viewport } from './protocol.ts';
|
|
2
|
+
export { isChildMessage, isParentMessage, YUBI } from './protocol.ts';
|
|
3
|
+
export type { ChildMessage, Frame, ParentMessage, Pin, Target, Unmarked, Viewport };
|
|
4
|
+
export type PickerOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Origin(s) allowed to host the review panel; messages from anywhere else are ignored.
|
|
7
|
+
* With several, the one framing the document (ancestorOrigins / referrer) is used; when that
|
|
8
|
+
* is unknown, messages go to every allowed origin until one has sent a valid message.
|
|
9
|
+
*/
|
|
10
|
+
parentOrigin: string | string[];
|
|
11
|
+
parent?: Window;
|
|
12
|
+
doc?: Document;
|
|
13
|
+
/** Milliseconds between route checks. */
|
|
14
|
+
routeEveryMs?: number;
|
|
15
|
+
};
|
|
16
|
+
export type PickerHandle = {
|
|
17
|
+
start(): void;
|
|
18
|
+
stop(): void;
|
|
19
|
+
clear(id?: number): void;
|
|
20
|
+
setPins(pins: Pin[]): void;
|
|
21
|
+
readonly picking: boolean;
|
|
22
|
+
readonly selection: readonly Target[];
|
|
23
|
+
destroy(): void;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Runs inside the app document: covers it with a glass pane while picking, draws hover/selection
|
|
27
|
+
* boxes and comment pins, and talks to the review panel through `postMessage` only.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createPicker(options: PickerOptions): PickerHandle;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { describe, label } from "./inspect.js";
|
|
2
|
+
import { isParentMessage, YUBI, } from "./protocol.js";
|
|
3
|
+
export { isChildMessage, isParentMessage, YUBI } from "./protocol.js";
|
|
4
|
+
const TYPING = 'input, textarea, [contenteditable=""], [contenteditable="true"]';
|
|
5
|
+
const ACCENT = '#f0883e';
|
|
6
|
+
const INK = '#111';
|
|
7
|
+
const MONO = 'ui-monospace, "JetBrains Mono", "SF Mono", monospace';
|
|
8
|
+
const SANS = 'ui-sans-serif, system-ui, sans-serif';
|
|
9
|
+
const routeOf = (win) => win.location.pathname + win.location.search + win.location.hash;
|
|
10
|
+
function framingOrigin(doc) {
|
|
11
|
+
const ancestors = doc.location.ancestorOrigins;
|
|
12
|
+
if (ancestors?.length)
|
|
13
|
+
return ancestors[0];
|
|
14
|
+
try {
|
|
15
|
+
return doc.referrer ? new URL(doc.referrer).origin : undefined;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Runs inside the app document: covers it with a glass pane while picking, draws hover/selection
|
|
23
|
+
* boxes and comment pins, and talks to the review panel through `postMessage` only.
|
|
24
|
+
*/
|
|
25
|
+
export function createPicker(options) {
|
|
26
|
+
const doc = options.doc ?? document;
|
|
27
|
+
const win = doc.defaultView;
|
|
28
|
+
const parent = options.parent ?? win.parent;
|
|
29
|
+
const allowed = [options.parentOrigin].flat().map((o) => new URL(o).origin);
|
|
30
|
+
let origin = allowed.find((o) => o === framingOrigin(doc));
|
|
31
|
+
const root = doc.createElement('div');
|
|
32
|
+
root.setAttribute('data-yubi', 'root');
|
|
33
|
+
root.style.cssText = 'position:fixed;inset:0;z-index:2147483646;pointer-events:none;';
|
|
34
|
+
const overlay = doc.createElement('div');
|
|
35
|
+
overlay.setAttribute('data-yubi', 'overlay');
|
|
36
|
+
overlay.style.cssText = 'position:absolute;inset:0;overflow:hidden;pointer-events:none;';
|
|
37
|
+
const glass = doc.createElement('div');
|
|
38
|
+
glass.setAttribute('data-yubi', 'glass');
|
|
39
|
+
glass.style.cssText =
|
|
40
|
+
'position:absolute;inset:0;cursor:crosshair;pointer-events:auto;display:none;';
|
|
41
|
+
root.append(overlay, glass);
|
|
42
|
+
doc.documentElement.append(root);
|
|
43
|
+
let picking = false;
|
|
44
|
+
let hover = null;
|
|
45
|
+
let selection = [];
|
|
46
|
+
let pins = [];
|
|
47
|
+
const refs = new Map();
|
|
48
|
+
let route = routeOf(win);
|
|
49
|
+
let raf = 0;
|
|
50
|
+
const send = (message) => {
|
|
51
|
+
const data = { ...message, yubi: YUBI };
|
|
52
|
+
for (const o of origin ? [origin] : allowed)
|
|
53
|
+
parent.postMessage(data, o);
|
|
54
|
+
};
|
|
55
|
+
const viewport = () => ({ width: win.innerWidth, height: win.innerHeight });
|
|
56
|
+
const elementAt = (x, y) => doc.elementsFromPoint(x, y).find((el) => !root.contains(el)) ?? null;
|
|
57
|
+
function setPicking(on) {
|
|
58
|
+
if (picking === on)
|
|
59
|
+
return;
|
|
60
|
+
picking = on;
|
|
61
|
+
glass.style.display = on ? 'block' : 'none';
|
|
62
|
+
if (!on)
|
|
63
|
+
setHover(null);
|
|
64
|
+
send({ type: 'pick:state', picking });
|
|
65
|
+
}
|
|
66
|
+
function setHover(el) {
|
|
67
|
+
if ((hover?.el ?? null) === el)
|
|
68
|
+
return;
|
|
69
|
+
hover = el ? { el, info: describe(el) } : null;
|
|
70
|
+
send({ type: 'pick:hover', target: hover?.info ?? null });
|
|
71
|
+
}
|
|
72
|
+
function setSelection(next) {
|
|
73
|
+
selection = next;
|
|
74
|
+
send({
|
|
75
|
+
type: 'pick:selected',
|
|
76
|
+
targets: selection.map((s) => s.info),
|
|
77
|
+
route: routeOf(win),
|
|
78
|
+
viewport: viewport(),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function pick(el, additive) {
|
|
82
|
+
const i = selection.findIndex((s) => s.el === el);
|
|
83
|
+
if (additive) {
|
|
84
|
+
setSelection(i >= 0 ? selection.filter((_, j) => j !== i) : [...selection, { el, info: describe(el) }]);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
setSelection([{ el, info: describe(el) }]);
|
|
88
|
+
setPicking(false);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function back() {
|
|
92
|
+
if (picking)
|
|
93
|
+
setPicking(false);
|
|
94
|
+
else if (selection.length)
|
|
95
|
+
setSelection([]);
|
|
96
|
+
else
|
|
97
|
+
send({ type: 'pick:cancel' });
|
|
98
|
+
}
|
|
99
|
+
function onKey(e) {
|
|
100
|
+
if (e.key === 'Escape')
|
|
101
|
+
return back();
|
|
102
|
+
const typing = e.target?.closest?.(TYPING);
|
|
103
|
+
if (!typing && (e.key === 'c' || e.key === 'C') && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
setPicking(!picking);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function onWheel(e) {
|
|
109
|
+
for (let node = elementAt(e.clientX, e.clientY); node; node = node.parentElement) {
|
|
110
|
+
const style = win.getComputedStyle(node);
|
|
111
|
+
if (/(auto|scroll)/.test(style.overflowY + style.overflowX)) {
|
|
112
|
+
const before = node.scrollTop + node.scrollLeft;
|
|
113
|
+
node.scrollBy(e.deltaX, e.deltaY);
|
|
114
|
+
if (node.scrollTop + node.scrollLeft !== before)
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
win.scrollBy(e.deltaX, e.deltaY);
|
|
119
|
+
}
|
|
120
|
+
function onMessage(e) {
|
|
121
|
+
if (e.source !== parent || !isParentMessage(e.data))
|
|
122
|
+
return;
|
|
123
|
+
if (origin ? e.origin !== origin : !allowed.includes(e.origin))
|
|
124
|
+
return;
|
|
125
|
+
origin = e.origin;
|
|
126
|
+
const msg = e.data;
|
|
127
|
+
if (msg.type === 'pick:start')
|
|
128
|
+
setPicking(true);
|
|
129
|
+
else if (msg.type === 'pick:stop')
|
|
130
|
+
setPicking(false);
|
|
131
|
+
else if (msg.type === 'pick:clear')
|
|
132
|
+
clear(msg.id);
|
|
133
|
+
else
|
|
134
|
+
setPins(msg.pins);
|
|
135
|
+
}
|
|
136
|
+
function clear(id) {
|
|
137
|
+
if (id !== undefined && selection.length)
|
|
138
|
+
refs.set(id, selection.map((s) => s.el));
|
|
139
|
+
if (selection.length)
|
|
140
|
+
setSelection([]);
|
|
141
|
+
}
|
|
142
|
+
function setPins(next) {
|
|
143
|
+
pins = next;
|
|
144
|
+
}
|
|
145
|
+
function locatePin(pin) {
|
|
146
|
+
const kept = refs.get(pin.id)?.find((el) => el.isConnected);
|
|
147
|
+
if (kept)
|
|
148
|
+
return kept;
|
|
149
|
+
try {
|
|
150
|
+
return doc.querySelector(pin.selector) ?? undefined;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const nodes = new Map();
|
|
157
|
+
function place(el, x, y, width, height) {
|
|
158
|
+
el.style.left = `${x}px`;
|
|
159
|
+
el.style.top = `${y}px`;
|
|
160
|
+
if (width !== undefined)
|
|
161
|
+
el.style.width = `${width}px`;
|
|
162
|
+
if (height !== undefined)
|
|
163
|
+
el.style.height = `${height}px`;
|
|
164
|
+
}
|
|
165
|
+
function box(key, rect, kind, text) {
|
|
166
|
+
let el = nodes.get(key);
|
|
167
|
+
if (!el) {
|
|
168
|
+
el = doc.createElement('div');
|
|
169
|
+
el.setAttribute('data-yubi', kind);
|
|
170
|
+
el.style.cssText = `position:absolute;border:2px ${kind === 'hover' ? 'dashed' : 'solid'} ${ACCENT};border-radius:3px;background:rgb(240 136 62 / ${kind === 'hover' ? 0.05 : 0.08});box-sizing:border-box;`;
|
|
171
|
+
const tag = doc.createElement('span');
|
|
172
|
+
tag.setAttribute('data-yubi', 'label');
|
|
173
|
+
tag.style.cssText = `position:absolute;top:-20px;left:-2px;padding:1px 6px;border-radius:3px 3px 3px 0;background:${ACCENT};color:${INK};font:11px/18px ${MONO};white-space:nowrap;`;
|
|
174
|
+
el.append(tag);
|
|
175
|
+
nodes.set(key, el);
|
|
176
|
+
}
|
|
177
|
+
place(el, rect.x, rect.y, rect.width, rect.height);
|
|
178
|
+
const tag = el.firstChild;
|
|
179
|
+
if (tag.textContent !== text)
|
|
180
|
+
tag.textContent = text;
|
|
181
|
+
return el;
|
|
182
|
+
}
|
|
183
|
+
function pinNode(pin, rect) {
|
|
184
|
+
const key = `pin:${pin.id}`;
|
|
185
|
+
let el = nodes.get(key);
|
|
186
|
+
if (!el) {
|
|
187
|
+
el = doc.createElement('button');
|
|
188
|
+
el.type = 'button';
|
|
189
|
+
el.setAttribute('data-yubi', 'pin');
|
|
190
|
+
el.setAttribute('data-id', String(pin.id));
|
|
191
|
+
el.textContent = String(pin.id);
|
|
192
|
+
el.title = `Open comment #${pin.id}`;
|
|
193
|
+
el.style.cssText = `position:absolute;width:22px;height:22px;margin:-11px 0 0 -11px;padding:0;border:0;border-radius:11px 11px 11px 2px;background:${ACCENT};color:${INK};font:600 11px/22px ${SANS};text-align:center;pointer-events:auto;cursor:pointer;box-shadow:0 1px 4px rgb(0 0 0 / 0.4);`;
|
|
194
|
+
el.onclick = () => send({ type: 'pin:open', id: pin.id });
|
|
195
|
+
nodes.set(key, el);
|
|
196
|
+
}
|
|
197
|
+
place(el, rect.x + rect.width, rect.y);
|
|
198
|
+
return el;
|
|
199
|
+
}
|
|
200
|
+
function draw() {
|
|
201
|
+
const layers = [];
|
|
202
|
+
if (picking && hover?.el.isConnected && !selection.some((s) => s.el === hover?.el)) {
|
|
203
|
+
layers.push(box('hover', hover.el.getBoundingClientRect(), 'hover', label(hover.info)));
|
|
204
|
+
}
|
|
205
|
+
selection.forEach((s, i) => {
|
|
206
|
+
if (s.el.isConnected)
|
|
207
|
+
layers.push(box(`sel:${i}`, s.el.getBoundingClientRect(), 'selected', label(s.info)));
|
|
208
|
+
});
|
|
209
|
+
for (const pin of pins) {
|
|
210
|
+
const el = locatePin(pin);
|
|
211
|
+
if (el)
|
|
212
|
+
layers.push(pinNode(pin, el.getBoundingClientRect()));
|
|
213
|
+
}
|
|
214
|
+
for (const [key, el] of nodes)
|
|
215
|
+
if (!layers.includes(el))
|
|
216
|
+
nodes.delete(key);
|
|
217
|
+
if (layers.length !== overlay.childNodes.length ||
|
|
218
|
+
layers.some((el, i) => overlay.childNodes[i] !== el))
|
|
219
|
+
overlay.replaceChildren(...layers);
|
|
220
|
+
raf = win.requestAnimationFrame(draw);
|
|
221
|
+
}
|
|
222
|
+
const onMove = (e) => setHover(elementAt(e.clientX, e.clientY));
|
|
223
|
+
const onLeave = () => setHover(null);
|
|
224
|
+
const onClick = (e) => {
|
|
225
|
+
const el = elementAt(e.clientX, e.clientY);
|
|
226
|
+
if (el)
|
|
227
|
+
pick(el, e.shiftKey || e.metaKey || e.ctrlKey);
|
|
228
|
+
};
|
|
229
|
+
const syncRoute = () => {
|
|
230
|
+
const next = routeOf(win);
|
|
231
|
+
if (next === route)
|
|
232
|
+
return;
|
|
233
|
+
route = next;
|
|
234
|
+
send({ type: 'route', route });
|
|
235
|
+
};
|
|
236
|
+
glass.addEventListener('mousemove', onMove);
|
|
237
|
+
glass.addEventListener('mouseleave', onLeave);
|
|
238
|
+
glass.addEventListener('click', onClick);
|
|
239
|
+
glass.addEventListener('wheel', onWheel, { passive: true });
|
|
240
|
+
win.addEventListener('keydown', onKey, true);
|
|
241
|
+
win.addEventListener('message', onMessage);
|
|
242
|
+
const routeTimer = win.setInterval(syncRoute, options.routeEveryMs ?? 400);
|
|
243
|
+
raf = win.requestAnimationFrame(draw);
|
|
244
|
+
send({ type: 'route', route });
|
|
245
|
+
return {
|
|
246
|
+
start: () => setPicking(true),
|
|
247
|
+
stop: () => setPicking(false),
|
|
248
|
+
clear,
|
|
249
|
+
setPins,
|
|
250
|
+
get picking() {
|
|
251
|
+
return picking;
|
|
252
|
+
},
|
|
253
|
+
get selection() {
|
|
254
|
+
return selection.map((s) => s.info);
|
|
255
|
+
},
|
|
256
|
+
destroy() {
|
|
257
|
+
win.cancelAnimationFrame(raf);
|
|
258
|
+
win.clearInterval(routeTimer);
|
|
259
|
+
win.removeEventListener('keydown', onKey, true);
|
|
260
|
+
win.removeEventListener('message', onMessage);
|
|
261
|
+
root.remove();
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.js","sourceRoot":"","sources":["../../src/picker/picker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Every message in both directions carries this marker; anything without it is ignored. */
|
|
2
|
+
export declare const YUBI: 1;
|
|
3
|
+
export type Frame = {
|
|
4
|
+
type: string;
|
|
5
|
+
file?: string;
|
|
6
|
+
line?: number;
|
|
7
|
+
column?: number;
|
|
8
|
+
name?: string;
|
|
9
|
+
};
|
|
10
|
+
export type Target = {
|
|
11
|
+
tag: string;
|
|
12
|
+
selector: string;
|
|
13
|
+
text: string;
|
|
14
|
+
html: string;
|
|
15
|
+
attrs: Record<string, string>;
|
|
16
|
+
rect: {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
};
|
|
22
|
+
source?: {
|
|
23
|
+
file: string;
|
|
24
|
+
line: number;
|
|
25
|
+
column: number;
|
|
26
|
+
};
|
|
27
|
+
stack: Frame[];
|
|
28
|
+
};
|
|
29
|
+
export type Pin = {
|
|
30
|
+
id: number;
|
|
31
|
+
selector: string;
|
|
32
|
+
};
|
|
33
|
+
export type Viewport = {
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
};
|
|
37
|
+
type Marked<T> = T & {
|
|
38
|
+
yubi: typeof YUBI;
|
|
39
|
+
};
|
|
40
|
+
/** A message before the marker is stamped on. */
|
|
41
|
+
export type Unmarked<T> = T extends unknown ? Omit<T, 'yubi'> : never;
|
|
42
|
+
/** Parent window → app document. */
|
|
43
|
+
export type ParentMessage = Marked<{
|
|
44
|
+
type: 'pick:start';
|
|
45
|
+
} | {
|
|
46
|
+
type: 'pick:stop';
|
|
47
|
+
}
|
|
48
|
+
/** Drops the selection; `id` records it as the targets of comment #id so its pin sticks to the picked elements. */
|
|
49
|
+
| {
|
|
50
|
+
type: 'pick:clear';
|
|
51
|
+
id?: number;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'pins:set';
|
|
54
|
+
pins: Pin[];
|
|
55
|
+
}>;
|
|
56
|
+
/** App document → parent window. */
|
|
57
|
+
export type ChildMessage = Marked<{
|
|
58
|
+
type: 'pick:state';
|
|
59
|
+
picking: boolean;
|
|
60
|
+
} | {
|
|
61
|
+
type: 'pick:hover';
|
|
62
|
+
target: Target | null;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'pick:selected';
|
|
65
|
+
targets: Target[];
|
|
66
|
+
route: string;
|
|
67
|
+
viewport: Viewport;
|
|
68
|
+
} | {
|
|
69
|
+
type: 'pick:cancel';
|
|
70
|
+
} | {
|
|
71
|
+
type: 'pin:open';
|
|
72
|
+
id: number;
|
|
73
|
+
} | {
|
|
74
|
+
type: 'route';
|
|
75
|
+
route: string;
|
|
76
|
+
}>;
|
|
77
|
+
export declare const isParentMessage: (data: unknown) => data is ParentMessage;
|
|
78
|
+
export declare const isChildMessage: (data: unknown) => data is ChildMessage;
|
|
79
|
+
export {};
|