@slowcook-ai/review-overlay 0.1.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/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/comment-format.d.ts +82 -0
- package/dist/comment-format.d.ts.map +1 -0
- package/dist/comment-format.js +102 -0
- package/dist/comment-format.js.map +1 -0
- package/dist/github.d.ts +44 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +70 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/overlay.d.ts +39 -0
- package/dist/react/overlay.d.ts.map +1 -0
- package/dist/react/overlay.js +317 -0
- package/dist/react/overlay.js.map +1 -0
- package/dist/selector.d.ts +34 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/selector.js +235 -0
- package/dist/selector.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Amin Azar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# @slowcook-ai/review-overlay
|
|
2
|
+
|
|
3
|
+
> Floating review overlay for slowcook mock previews. PMs leave element-anchored comments by clicking the element; comments POST to the mockup PR via a GitHub PAT. Plate parses them back out for amendments. Ships in slowcook 0.16-α.6.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
When mounted into the consumer's mock app:
|
|
8
|
+
|
|
9
|
+
- A floating mode toggle (top-right) shows three modes: **Nav** / **💬 Comment** / **✅ Approve**.
|
|
10
|
+
- In **Comment** mode, clicks on any element open a sidebar where the PM types prose. On submit, the overlay POSTs a structured comment to the configured PR.
|
|
11
|
+
- In **Approve** mode, the PM clicks an element (or just toggles back to Nav after one click) and the overlay posts an approval comment with a hidden marker that plate detects.
|
|
12
|
+
- Each comment carries the element's stable selector (id > data-testid > role+name > tag.classes:nth-child > XPath fallback), bounding box, viewport size + color scheme, current URL, and user agent — both as human-readable markdown AND as a JSON payload inside an HTML comment that plate parses.
|
|
13
|
+
|
|
14
|
+
The package has TWO entries:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// Framework-free core (parser, selector, GitHub submit, PAT storage).
|
|
18
|
+
// This is what plate imports server-side to decode review comments.
|
|
19
|
+
import { parseReviewComment, extractSelector, submitComment } from "@slowcook-ai/review-overlay";
|
|
20
|
+
|
|
21
|
+
// React shell (mounted into the mock app's root layout).
|
|
22
|
+
import { SlowcookReviewOverlay } from "@slowcook-ai/review-overlay/react";
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Mount only the `/react` entry in the consumer's app; the core entry has zero React dependency.
|
|
26
|
+
|
|
27
|
+
## Mounting in the mock app
|
|
28
|
+
|
|
29
|
+
The mock app scaffold (`slowcook init mock`) has a placeholder comment in `mock/src/app/layout.tsx`. Replace it with:
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { SlowcookReviewOverlay } from "@slowcook-ai/review-overlay/react";
|
|
33
|
+
|
|
34
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
35
|
+
return (
|
|
36
|
+
<html lang="en">
|
|
37
|
+
<body className="bg-background text-foreground antialiased">
|
|
38
|
+
<ScenarioRegistryProvider registry={registry}>
|
|
39
|
+
{children}
|
|
40
|
+
<SlowcookReviewOverlay
|
|
41
|
+
enabled={process.env["NEXT_PUBLIC_SLOWCOOK_REVIEW"] === "1"}
|
|
42
|
+
owner={process.env["NEXT_PUBLIC_SLOWCOOK_OWNER"] ?? ""}
|
|
43
|
+
repo={process.env["NEXT_PUBLIC_SLOWCOOK_REPO"] ?? ""}
|
|
44
|
+
prNumber={parseInt(process.env["NEXT_PUBLIC_SLOWCOOK_PR_NUMBER"] ?? "0", 10)}
|
|
45
|
+
storyId={process.env["NEXT_PUBLIC_SLOWCOOK_STORY_ID"] ?? null}
|
|
46
|
+
/>
|
|
47
|
+
</ScenarioRegistryProvider>
|
|
48
|
+
</body>
|
|
49
|
+
</html>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The `enabled` gate keeps the overlay out of production-style builds. Slowcook's preview-deploy workflow (0.16-α.5) sets `NEXT_PUBLIC_SLOWCOOK_REVIEW=1` plus the owner/repo/PR env vars when it builds the mock for a `slowcook-mockup` PR.
|
|
55
|
+
|
|
56
|
+
## How a comment lands in the PR
|
|
57
|
+
|
|
58
|
+
1. PM clicks the floating toggle → **💬 Comment**.
|
|
59
|
+
2. Coral tint overlays the viewport; subsequent clicks are captured (`{ capture: true, preventDefault }`) — the underlying button doesn't fire.
|
|
60
|
+
3. PM clicks the element they want to comment on. Sidebar opens with the extracted selector pre-filled and a textarea.
|
|
61
|
+
4. PM types prose, hits Submit.
|
|
62
|
+
5. The overlay reads the GitHub PAT from `localStorage[slowcook.review-overlay.pat.{owner}/{repo}]`. First-time submits prompt for one (token scope: `public_repo` or `repo`).
|
|
63
|
+
6. POST to `https://api.github.com/repos/{owner}/{repo}/issues/{pr}/comments` with body:
|
|
64
|
+
|
|
65
|
+
```markdown
|
|
66
|
+
### Review comment — `#unread-badge`
|
|
67
|
+
|
|
68
|
+
**Element:** `span` · "3"
|
|
69
|
+
**Viewport:** 390×844 dark (dpr 3)
|
|
70
|
+
**URL:** http://mock-4015.preview.example.com/u/amin?scenario=017
|
|
71
|
+
|
|
72
|
+
> Pin button looks dead.
|
|
73
|
+
|
|
74
|
+
<!--
|
|
75
|
+
slowcook:review-overlay
|
|
76
|
+
{"slowcook_overlay_version":"0.1.0","story_id":"017","element":{"selector":"#unread-badge","fallback_selector":"span.badge","strategy":"id","tag":"span","text_hint":"3","bbox":{"x":142,"y":73,"w":22,"h":22}},"viewport":{"width":390,"height":844,"colorScheme":"dark","dpr":3},"url":"...","timestamp":"...","prose":"...","user_agent":"..."}
|
|
77
|
+
-->
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
7. Plate (slowcook 0.16-α.7) reads the PR's comments, calls `parseReviewComment(body)` for each, and acts.
|
|
81
|
+
|
|
82
|
+
## Selector strategy
|
|
83
|
+
|
|
84
|
+
Stable-selector priority (matches the design doc; first non-null wins):
|
|
85
|
+
|
|
86
|
+
| Strategy | Example | When it applies |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `id` | `#unread-badge` | Element has a meaningful `id` (skips React `useId` patterns like `:r3:`, Radix's `radix-:r…`, Headless UI's `headlessui-…`) |
|
|
89
|
+
| `data-testid` | `[data-testid="save-btn"]` | Element has `data-testid` |
|
|
90
|
+
| `role-name` | `button[aria-label="Sign in"]` | Has explicit/implicit role + accessible name (aria-label, aria-labelledby, `<label for>`, button/link textContent) |
|
|
91
|
+
| `tag-classes` | `span.badge.counter:nth-child(2)` | Picks first 2 non-utility class names; adds `:nth-child(N)` when parent has multiple same-tag children. Skips Tailwind utilities, emotion `css-XXXX` hashes, CSS-modules `_XXXX` hashes |
|
|
92
|
+
| `xpath` | `/html/body/div/span[2]` | Last resort — always works |
|
|
93
|
+
|
|
94
|
+
The fallback (one rung lower than the chosen strategy) is also captured so plate has a degraded option when the page changes between submit and reconciliation.
|
|
95
|
+
|
|
96
|
+
## PAT storage
|
|
97
|
+
|
|
98
|
+
Stored under `localStorage["slowcook.review-overlay.pat.{owner}/{repo}"]`. Scoped per repo — the same browser can hold multiple consumers' tokens without collision.
|
|
99
|
+
|
|
100
|
+
The PAT never leaves the browser except on a direct fetch to GitHub's API. To revoke / rotate, clear the localStorage entry (or `clearPat(window.localStorage, { owner, repo })` from the console).
|
|
101
|
+
|
|
102
|
+
A future "Mode B" — consumer-hosted submit endpoint — would let the consumer's backend hold a server-side token instead of the PM's PAT. Deferred.
|
|
103
|
+
|
|
104
|
+
## Bundle weight
|
|
105
|
+
|
|
106
|
+
| Entry | Approx gz size |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `/` (core: parser + selector + github + format) | ~3 KB |
|
|
109
|
+
| `/react` (overlay component) | ~6 KB |
|
|
110
|
+
|
|
111
|
+
No html2canvas yet; α.6 ships the bounding box + selector + viewport metadata and the user can paste a screenshot manually if needed. Auto-screenshot via canvas API queued for a follow-up alpha.
|
|
112
|
+
|
|
113
|
+
## See also
|
|
114
|
+
|
|
115
|
+
- [`docs/plans/0.16-mock-app.md`](https://github.com/aminazar/slowcook/blob/main/docs/plans/0.16-mock-app.md) — the architecture this fits into
|
|
116
|
+
- [`docs/plans/0.13.1-review-overlay.md`](https://github.com/aminazar/slowcook/blob/main/docs/plans/0.13.1-review-overlay.md) — original design doc; this is its v1 implementation
|
|
117
|
+
- [`docs/operating-guide.md`](https://github.com/aminazar/slowcook/blob/main/docs/operating-guide.md) — sets up the SSH preview deploy that delivers the mock app to the PM
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment markdown + JSON-payload formatter — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* The overlay submits each comment as a single GitHub PR comment whose
|
|
5
|
+
* body is:
|
|
6
|
+
*
|
|
7
|
+
* - human-readable markdown (selector, viewport, prose)
|
|
8
|
+
* - HTML-comment-hidden JSON payload (the structured data plate parses)
|
|
9
|
+
*
|
|
10
|
+
* Plate's parser greps for the payload marker; humans see the rendered
|
|
11
|
+
* markdown. Same idea as the cost-marker rollups slowcook already uses.
|
|
12
|
+
*
|
|
13
|
+
* Pure function; no DOM access.
|
|
14
|
+
*/
|
|
15
|
+
import type { ExtractedSelector } from "./selector.js";
|
|
16
|
+
export interface ViewportInfo {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
/** Color scheme: light / dark / no-preference. */
|
|
20
|
+
colorScheme: "light" | "dark" | "no-preference";
|
|
21
|
+
/** Device pixel ratio. */
|
|
22
|
+
dpr: number;
|
|
23
|
+
}
|
|
24
|
+
export interface ReviewCommentPayload {
|
|
25
|
+
slowcook_overlay_version: string;
|
|
26
|
+
story_id: string | null;
|
|
27
|
+
url: string;
|
|
28
|
+
timestamp: string;
|
|
29
|
+
prose: string;
|
|
30
|
+
element: {
|
|
31
|
+
selector: string;
|
|
32
|
+
fallback_selector: string | null;
|
|
33
|
+
strategy: ExtractedSelector["strategy"];
|
|
34
|
+
tag: string;
|
|
35
|
+
text_hint: string | null;
|
|
36
|
+
/** Bounding box in CSS pixels at submit time. */
|
|
37
|
+
bbox: {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
w: number;
|
|
41
|
+
h: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
viewport: ViewportInfo;
|
|
45
|
+
user_agent: string;
|
|
46
|
+
}
|
|
47
|
+
export declare const PAYLOAD_MARKER = "slowcook:review-overlay";
|
|
48
|
+
export interface FormatArgs {
|
|
49
|
+
payload: ReviewCommentPayload;
|
|
50
|
+
/** Optional inline screenshot data URL (image/png). */
|
|
51
|
+
screenshotDataUrl?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Render the full comment body (markdown + hidden JSON). The hidden
|
|
55
|
+
* JSON is wrapped in an HTML comment with a stable marker so plate's
|
|
56
|
+
* parser can locate + decode it idempotently.
|
|
57
|
+
*/
|
|
58
|
+
export declare function formatReviewComment(args: FormatArgs): string;
|
|
59
|
+
/**
|
|
60
|
+
* Reverse — given a rendered comment body, extract the JSON payload if
|
|
61
|
+
* present. Returns null when the body has no payload (i.e., it isn't
|
|
62
|
+
* a review-overlay comment).
|
|
63
|
+
*
|
|
64
|
+
* Plate uses this to ingest each review-overlay comment on a mockup PR.
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseReviewComment(body: string): ReviewCommentPayload | null;
|
|
67
|
+
export declare function buildPayload(args: {
|
|
68
|
+
overlayVersion: string;
|
|
69
|
+
storyId: string | null;
|
|
70
|
+
url: string;
|
|
71
|
+
prose: string;
|
|
72
|
+
selector: ExtractedSelector;
|
|
73
|
+
bbox: {
|
|
74
|
+
x: number;
|
|
75
|
+
y: number;
|
|
76
|
+
w: number;
|
|
77
|
+
h: number;
|
|
78
|
+
};
|
|
79
|
+
viewport: ViewportInfo;
|
|
80
|
+
userAgent: string;
|
|
81
|
+
}): ReviewCommentPayload;
|
|
82
|
+
//# sourceMappingURL=comment-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-format.d.ts","sourceRoot":"","sources":["../src/comment-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,eAAe,CAAC;IAChD,0BAA0B;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACnC,wBAAwB,EAAE,MAAM,CAAC;IACjC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,QAAQ,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;QACxC,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,iDAAiD;QACjD,IAAI,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KACtD,CAAC;IACF,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,cAAc,4BAA4B,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,uDAAuD;IACvD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CA8B5D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI,CAgB5E;AAeD,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,oBAAoB,CAkBvB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comment markdown + JSON-payload formatter — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* The overlay submits each comment as a single GitHub PR comment whose
|
|
5
|
+
* body is:
|
|
6
|
+
*
|
|
7
|
+
* - human-readable markdown (selector, viewport, prose)
|
|
8
|
+
* - HTML-comment-hidden JSON payload (the structured data plate parses)
|
|
9
|
+
*
|
|
10
|
+
* Plate's parser greps for the payload marker; humans see the rendered
|
|
11
|
+
* markdown. Same idea as the cost-marker rollups slowcook already uses.
|
|
12
|
+
*
|
|
13
|
+
* Pure function; no DOM access.
|
|
14
|
+
*/
|
|
15
|
+
export const PAYLOAD_MARKER = "slowcook:review-overlay";
|
|
16
|
+
/**
|
|
17
|
+
* Render the full comment body (markdown + hidden JSON). The hidden
|
|
18
|
+
* JSON is wrapped in an HTML comment with a stable marker so plate's
|
|
19
|
+
* parser can locate + decode it idempotently.
|
|
20
|
+
*/
|
|
21
|
+
export function formatReviewComment(args) {
|
|
22
|
+
const { payload, screenshotDataUrl } = args;
|
|
23
|
+
const lines = [];
|
|
24
|
+
lines.push(`### Review comment — \`${payload.element.selector}\``);
|
|
25
|
+
lines.push("");
|
|
26
|
+
lines.push(`**Element:** \`${payload.element.tag}\` ${payload.element.text_hint ? `· "${payload.element.text_hint}"` : ""}`);
|
|
27
|
+
lines.push(`**Viewport:** ${payload.viewport.width}×${payload.viewport.height} ${payload.viewport.colorScheme} (dpr ${payload.viewport.dpr})`);
|
|
28
|
+
lines.push(`**URL:** ${payload.url}`);
|
|
29
|
+
lines.push("");
|
|
30
|
+
lines.push(`> ${payload.prose.split("\n").join("\n> ")}`);
|
|
31
|
+
lines.push("");
|
|
32
|
+
if (screenshotDataUrl) {
|
|
33
|
+
lines.push(``);
|
|
34
|
+
lines.push("");
|
|
35
|
+
}
|
|
36
|
+
// Hidden JSON for plate. Wrap in HTML comment + payload marker so the
|
|
37
|
+
// parser can grep + decode without parsing markdown structure.
|
|
38
|
+
lines.push("<!--");
|
|
39
|
+
lines.push(PAYLOAD_MARKER);
|
|
40
|
+
lines.push(JSON.stringify(payload));
|
|
41
|
+
lines.push("-->");
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Reverse — given a rendered comment body, extract the JSON payload if
|
|
46
|
+
* present. Returns null when the body has no payload (i.e., it isn't
|
|
47
|
+
* a review-overlay comment).
|
|
48
|
+
*
|
|
49
|
+
* Plate uses this to ingest each review-overlay comment on a mockup PR.
|
|
50
|
+
*/
|
|
51
|
+
export function parseReviewComment(body) {
|
|
52
|
+
const idx = body.indexOf(PAYLOAD_MARKER);
|
|
53
|
+
if (idx < 0)
|
|
54
|
+
return null;
|
|
55
|
+
// The JSON is on the line after the marker, before `-->`.
|
|
56
|
+
const tail = body.slice(idx + PAYLOAD_MARKER.length);
|
|
57
|
+
const closeIdx = tail.indexOf("-->");
|
|
58
|
+
const region = closeIdx < 0 ? tail : tail.slice(0, closeIdx);
|
|
59
|
+
const m = region.match(/\{[\s\S]*\}/);
|
|
60
|
+
if (!m)
|
|
61
|
+
return null;
|
|
62
|
+
try {
|
|
63
|
+
const parsed = JSON.parse(m[0]);
|
|
64
|
+
if (!isReviewCommentPayload(parsed))
|
|
65
|
+
return null;
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function isReviewCommentPayload(v) {
|
|
73
|
+
if (!v || typeof v !== "object")
|
|
74
|
+
return false;
|
|
75
|
+
const o = v;
|
|
76
|
+
return (typeof o["slowcook_overlay_version"] === "string" &&
|
|
77
|
+
typeof o["url"] === "string" &&
|
|
78
|
+
typeof o["timestamp"] === "string" &&
|
|
79
|
+
typeof o["prose"] === "string" &&
|
|
80
|
+
typeof o["element"] === "object" && o["element"] !== null &&
|
|
81
|
+
typeof o["viewport"] === "object" && o["viewport"] !== null);
|
|
82
|
+
}
|
|
83
|
+
export function buildPayload(args) {
|
|
84
|
+
return {
|
|
85
|
+
slowcook_overlay_version: args.overlayVersion,
|
|
86
|
+
story_id: args.storyId,
|
|
87
|
+
url: args.url,
|
|
88
|
+
timestamp: new Date().toISOString(),
|
|
89
|
+
prose: args.prose,
|
|
90
|
+
element: {
|
|
91
|
+
selector: args.selector.selector,
|
|
92
|
+
fallback_selector: args.selector.fallbackSelector,
|
|
93
|
+
strategy: args.selector.strategy,
|
|
94
|
+
tag: args.selector.tag,
|
|
95
|
+
text_hint: args.selector.textHint,
|
|
96
|
+
bbox: args.bbox,
|
|
97
|
+
},
|
|
98
|
+
viewport: args.viewport,
|
|
99
|
+
user_agent: args.userAgent,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=comment-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-format.js","sourceRoot":"","sources":["../src/comment-format.ts"],"names":[],"mappings":"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"}
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API submit + PAT storage — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* The overlay POSTs review comments directly from the browser using a
|
|
5
|
+
* PAT stored in localStorage. Mode A in the 0.13.1-overlay design;
|
|
6
|
+
* Mode B (consumer's own submit endpoint) deferred to a follow-up.
|
|
7
|
+
*
|
|
8
|
+
* Storage key is keyed by the {owner}/{repo} pair so the same browser
|
|
9
|
+
* can hold multiple consumers' tokens without collision.
|
|
10
|
+
*/
|
|
11
|
+
export interface RepoCoord {
|
|
12
|
+
owner: string;
|
|
13
|
+
repo: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function patStorageKey(repo: RepoCoord): string;
|
|
16
|
+
export declare function loadPat(storage: Storage, repo: RepoCoord): string | null;
|
|
17
|
+
export declare function savePat(storage: Storage, repo: RepoCoord, pat: string): void;
|
|
18
|
+
export declare function clearPat(storage: Storage, repo: RepoCoord): void;
|
|
19
|
+
export interface SubmitArgs extends RepoCoord {
|
|
20
|
+
pr: number;
|
|
21
|
+
pat: string;
|
|
22
|
+
body: string;
|
|
23
|
+
/** Override the API base; default https://api.github.com */
|
|
24
|
+
apiBase?: string;
|
|
25
|
+
/** Inject fetch — defaults to globalThis.fetch. Useful for tests. */
|
|
26
|
+
fetchImpl?: typeof fetch;
|
|
27
|
+
}
|
|
28
|
+
export interface SubmitOk {
|
|
29
|
+
ok: true;
|
|
30
|
+
commentId: number;
|
|
31
|
+
htmlUrl: string;
|
|
32
|
+
}
|
|
33
|
+
export interface SubmitErr {
|
|
34
|
+
ok: false;
|
|
35
|
+
status: number;
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
export type SubmitResult = SubmitOk | SubmitErr;
|
|
39
|
+
/**
|
|
40
|
+
* POST a comment to the given PR. Returns a tagged result rather than
|
|
41
|
+
* throwing so the React layer can render specific UI per failure mode.
|
|
42
|
+
*/
|
|
43
|
+
export declare function submitComment(args: SubmitArgs): Promise<SubmitResult>;
|
|
44
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAErD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAExE;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5E;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAEhE;AAED,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAuC3E"}
|
package/dist/github.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API submit + PAT storage — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* The overlay POSTs review comments directly from the browser using a
|
|
5
|
+
* PAT stored in localStorage. Mode A in the 0.13.1-overlay design;
|
|
6
|
+
* Mode B (consumer's own submit endpoint) deferred to a follow-up.
|
|
7
|
+
*
|
|
8
|
+
* Storage key is keyed by the {owner}/{repo} pair so the same browser
|
|
9
|
+
* can hold multiple consumers' tokens without collision.
|
|
10
|
+
*/
|
|
11
|
+
const PAT_STORAGE_KEY_PREFIX = "slowcook.review-overlay.pat.";
|
|
12
|
+
export function patStorageKey(repo) {
|
|
13
|
+
return `${PAT_STORAGE_KEY_PREFIX}${repo.owner}/${repo.repo}`;
|
|
14
|
+
}
|
|
15
|
+
export function loadPat(storage, repo) {
|
|
16
|
+
return storage.getItem(patStorageKey(repo));
|
|
17
|
+
}
|
|
18
|
+
export function savePat(storage, repo, pat) {
|
|
19
|
+
storage.setItem(patStorageKey(repo), pat);
|
|
20
|
+
}
|
|
21
|
+
export function clearPat(storage, repo) {
|
|
22
|
+
storage.removeItem(patStorageKey(repo));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* POST a comment to the given PR. Returns a tagged result rather than
|
|
26
|
+
* throwing so the React layer can render specific UI per failure mode.
|
|
27
|
+
*/
|
|
28
|
+
export async function submitComment(args) {
|
|
29
|
+
const fetchImpl = args.fetchImpl ?? globalThis.fetch;
|
|
30
|
+
const apiBase = args.apiBase ?? "https://api.github.com";
|
|
31
|
+
const url = `${apiBase}/repos/${encodeURIComponent(args.owner)}/${encodeURIComponent(args.repo)}/issues/${args.pr}/comments`;
|
|
32
|
+
let res;
|
|
33
|
+
try {
|
|
34
|
+
res = await fetchImpl(url, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
Authorization: `Bearer ${args.pat}`,
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
Accept: "application/vnd.github+json",
|
|
40
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({ body: args.body }),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
status: 0,
|
|
49
|
+
message: `network error: ${e.message}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
let detail = "";
|
|
54
|
+
try {
|
|
55
|
+
const j = (await res.json());
|
|
56
|
+
detail = j.message ?? "";
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// body wasn't JSON — keep detail empty
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
status: res.status,
|
|
64
|
+
message: detail || res.statusText,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const j = (await res.json());
|
|
68
|
+
return { ok: true, commentId: j.id, htmlUrl: j.html_url };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,sBAAsB,GAAG,8BAA8B,CAAC;AAO9D,MAAM,UAAU,aAAa,CAAC,IAAe;IAC3C,OAAO,GAAG,sBAAsB,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAgB,EAAE,IAAe;IACvD,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAgB,EAAE,IAAe,EAAE,GAAW;IACpE,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAgB,EAAE,IAAe;IACxD,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1C,CAAC;AA0BD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAgB;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,wBAAwB,CAAC;IACzD,MAAM,GAAG,GAAG,GAAG,OAAO,UAAU,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,EAAE,WAAW,CAAC;IAC7H,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACzB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,IAAI,CAAC,GAAG,EAAE;gBACnC,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,6BAA6B;gBACrC,sBAAsB,EAAE,YAAY;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,CAAC;YACT,OAAO,EAAE,kBAAmB,CAAW,CAAC,OAAO,EAAE;SAClD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyB,CAAC;YACrD,MAAM,GAAG,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;QACD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC,UAAU;SAClC,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAqC,CAAC;IACjE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5D,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@slowcook-ai/review-overlay` — public surface.
|
|
3
|
+
*
|
|
4
|
+
* Two entry points:
|
|
5
|
+
*
|
|
6
|
+
* import { ... } from "@slowcook-ai/review-overlay" // framework-free core
|
|
7
|
+
* import { SlowcookReviewOverlay } from "@slowcook-ai/review-overlay/react" // React shell
|
|
8
|
+
*
|
|
9
|
+
* The core entry has zero React dependency; plate (which lives in the
|
|
10
|
+
* cli package, server-side) imports `parseReviewComment` from here to
|
|
11
|
+
* decode review comments off the PR thread.
|
|
12
|
+
*/
|
|
13
|
+
export { PAYLOAD_MARKER, formatReviewComment, parseReviewComment, buildPayload, type ReviewCommentPayload, type ViewportInfo, type FormatArgs, } from "./comment-format.js";
|
|
14
|
+
export { extractSelector, type ExtractedSelector, } from "./selector.js";
|
|
15
|
+
export { loadPat, savePat, clearPat, patStorageKey, submitComment, type RepoCoord, type SubmitArgs, type SubmitResult, type SubmitOk, type SubmitErr, } from "./github.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,KAAK,iBAAiB,GACvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,OAAO,EACP,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,SAAS,GACf,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@slowcook-ai/review-overlay` — public surface.
|
|
3
|
+
*
|
|
4
|
+
* Two entry points:
|
|
5
|
+
*
|
|
6
|
+
* import { ... } from "@slowcook-ai/review-overlay" // framework-free core
|
|
7
|
+
* import { SlowcookReviewOverlay } from "@slowcook-ai/review-overlay/react" // React shell
|
|
8
|
+
*
|
|
9
|
+
* The core entry has zero React dependency; plate (which lives in the
|
|
10
|
+
* cli package, server-side) imports `parseReviewComment` from here to
|
|
11
|
+
* decode review comments off the PR thread.
|
|
12
|
+
*/
|
|
13
|
+
export { PAYLOAD_MARKER, formatReviewComment, parseReviewComment, buildPayload, } from "./comment-format.js";
|
|
14
|
+
export { extractSelector, } from "./selector.js";
|
|
15
|
+
export { loadPat, savePat, clearPat, patStorageKey, submitComment, } from "./github.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GAIb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,GAEhB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,OAAO,EACP,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,GAMd,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAmC,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <SlowcookReviewOverlay /> — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* Mounted into the consumer's mock-app root layout. Renders a floating
|
|
5
|
+
* mode toggle (nav / comment / approve). In comment mode, clicks on
|
|
6
|
+
* elements capture a selector + bbox + viewport metadata; the user
|
|
7
|
+
* types prose and submits to the mockup PR via PAT.
|
|
8
|
+
*
|
|
9
|
+
* Bundle weight is paid only when consumers mount it. The mock app
|
|
10
|
+
* scaffolded by `slowcook init mock` includes a code-comment placeholder
|
|
11
|
+
* but does NOT mount the overlay; consumers opt in by editing
|
|
12
|
+
* mock/src/app/layout.tsx after installing this package.
|
|
13
|
+
*
|
|
14
|
+
* Architecture:
|
|
15
|
+
* - Pure-React inline UI (no portal needed; the overlay's own
|
|
16
|
+
* fixed-position root sits above body)
|
|
17
|
+
* - Selector + comment-format + github logic lives in the framework-
|
|
18
|
+
* free modules in this package; the React shell wires events
|
|
19
|
+
* - Tailwind-style classes inlined — but every visible style is also
|
|
20
|
+
* set via `style={...}` so the overlay renders even without
|
|
21
|
+
* Tailwind in the host app
|
|
22
|
+
*/
|
|
23
|
+
import { type JSX } from "react";
|
|
24
|
+
export interface SlowcookReviewOverlayProps {
|
|
25
|
+
/** GitHub owner (e.g. "aminazar"). */
|
|
26
|
+
owner: string;
|
|
27
|
+
/** GitHub repo (e.g. "slowcook"). */
|
|
28
|
+
repo: string;
|
|
29
|
+
/** Pull-request number for the mockup PR being reviewed. */
|
|
30
|
+
prNumber: number;
|
|
31
|
+
/** Optional story id; included in the JSON payload. */
|
|
32
|
+
storyId?: string | null;
|
|
33
|
+
/** Render only when truthy; useful for `process.env.NEXT_PUBLIC_SLOWCOOK_REVIEW === "1"` gating. */
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
/** Overlay package version, included in the JSON payload. */
|
|
36
|
+
overlayVersion?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function SlowcookReviewOverlay(props: SlowcookReviewOverlayProps): JSX.Element | null;
|
|
39
|
+
//# sourceMappingURL=overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/react/overlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAA4C,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAc3E,MAAM,WAAW,0BAA0B;IACzC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAQD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAgL3F"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <SlowcookReviewOverlay /> — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* Mounted into the consumer's mock-app root layout. Renders a floating
|
|
5
|
+
* mode toggle (nav / comment / approve). In comment mode, clicks on
|
|
6
|
+
* elements capture a selector + bbox + viewport metadata; the user
|
|
7
|
+
* types prose and submits to the mockup PR via PAT.
|
|
8
|
+
*
|
|
9
|
+
* Bundle weight is paid only when consumers mount it. The mock app
|
|
10
|
+
* scaffolded by `slowcook init mock` includes a code-comment placeholder
|
|
11
|
+
* but does NOT mount the overlay; consumers opt in by editing
|
|
12
|
+
* mock/src/app/layout.tsx after installing this package.
|
|
13
|
+
*
|
|
14
|
+
* Architecture:
|
|
15
|
+
* - Pure-React inline UI (no portal needed; the overlay's own
|
|
16
|
+
* fixed-position root sits above body)
|
|
17
|
+
* - Selector + comment-format + github logic lives in the framework-
|
|
18
|
+
* free modules in this package; the React shell wires events
|
|
19
|
+
* - Tailwind-style classes inlined — but every visible style is also
|
|
20
|
+
* set via `style={...}` so the overlay renders even without
|
|
21
|
+
* Tailwind in the host app
|
|
22
|
+
*/
|
|
23
|
+
"use client";
|
|
24
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
25
|
+
import { useEffect, useState, useRef, useCallback } from "react";
|
|
26
|
+
import { extractSelector } from "../selector.js";
|
|
27
|
+
import { buildPayload, formatReviewComment, } from "../comment-format.js";
|
|
28
|
+
import { loadPat, savePat, submitComment, } from "../github.js";
|
|
29
|
+
const APPROVE_LABEL = "slowcook-mockup-approved";
|
|
30
|
+
const ACCENT = "#FF6B6B";
|
|
31
|
+
export function SlowcookReviewOverlay(props) {
|
|
32
|
+
const { owner, repo, prNumber, storyId = null, enabled = true } = props;
|
|
33
|
+
const overlayVersion = props.overlayVersion ?? "0.1.0";
|
|
34
|
+
const repoCoord = { owner, repo };
|
|
35
|
+
// Hooks must run unconditionally — render the null AFTER all hooks
|
|
36
|
+
// are declared. Bails early during SSR via the typeof window check.
|
|
37
|
+
const [mode, setMode] = useState("nav");
|
|
38
|
+
const [target, setTarget] = useState(null);
|
|
39
|
+
const [composerOpen, setComposerOpen] = useState(false);
|
|
40
|
+
const [submitting, setSubmitting] = useState(false);
|
|
41
|
+
const [feedback, setFeedback] = useState(null);
|
|
42
|
+
const composerRef = useRef(null);
|
|
43
|
+
// ESC exits comment/approve mode + closes composer.
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (typeof window === "undefined")
|
|
46
|
+
return;
|
|
47
|
+
function onKey(e) {
|
|
48
|
+
if (e.key === "Escape") {
|
|
49
|
+
setMode("nav");
|
|
50
|
+
setComposerOpen(false);
|
|
51
|
+
setTarget(null);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
window.addEventListener("keydown", onKey);
|
|
55
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
56
|
+
}, []);
|
|
57
|
+
// Capture clicks at the document level when in comment/approve mode.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (typeof window === "undefined")
|
|
60
|
+
return;
|
|
61
|
+
if (mode === "nav")
|
|
62
|
+
return;
|
|
63
|
+
function onClick(e) {
|
|
64
|
+
const el = e.target;
|
|
65
|
+
if (!el)
|
|
66
|
+
return;
|
|
67
|
+
// Don't capture clicks on the overlay's own UI.
|
|
68
|
+
if (composerRef.current && composerRef.current.contains(el))
|
|
69
|
+
return;
|
|
70
|
+
if (el.closest('[data-slowcook-overlay-ui="1"]'))
|
|
71
|
+
return;
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
e.stopPropagation();
|
|
74
|
+
if (mode === "comment") {
|
|
75
|
+
setTarget(el);
|
|
76
|
+
setComposerOpen(true);
|
|
77
|
+
}
|
|
78
|
+
else if (mode === "approve") {
|
|
79
|
+
void submitApproval();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
document.addEventListener("click", onClick, { capture: true });
|
|
83
|
+
return () => document.removeEventListener("click", onClick, { capture: true });
|
|
84
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
85
|
+
}, [mode]);
|
|
86
|
+
const submitApproval = useCallback(async () => {
|
|
87
|
+
setSubmitting(true);
|
|
88
|
+
setFeedback(null);
|
|
89
|
+
try {
|
|
90
|
+
const pat = ensurePat(repoCoord);
|
|
91
|
+
if (!pat) {
|
|
92
|
+
setFeedback("Approval cancelled — no PAT.");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const body = `### ✅ Mockup approved\n\nPM approved the mockup via the review overlay (\`${overlayVersion}\`).\n\nPlease apply the \`${APPROVE_LABEL}\` label.`;
|
|
96
|
+
const result = await submitComment({
|
|
97
|
+
owner: repoCoord.owner,
|
|
98
|
+
repo: repoCoord.repo,
|
|
99
|
+
pr: prNumber,
|
|
100
|
+
pat,
|
|
101
|
+
body,
|
|
102
|
+
});
|
|
103
|
+
if (result.ok) {
|
|
104
|
+
setFeedback(`Approval comment posted (#${result.commentId}).`);
|
|
105
|
+
setMode("nav");
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
setFeedback(`Approval failed: ${result.status} ${result.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
setSubmitting(false);
|
|
113
|
+
}
|
|
114
|
+
}, [overlayVersion, prNumber, repoCoord]);
|
|
115
|
+
const submitFromComposer = useCallback(async (prose) => {
|
|
116
|
+
if (!target)
|
|
117
|
+
return;
|
|
118
|
+
setSubmitting(true);
|
|
119
|
+
setFeedback(null);
|
|
120
|
+
try {
|
|
121
|
+
const pat = ensurePat(repoCoord);
|
|
122
|
+
if (!pat) {
|
|
123
|
+
setFeedback("Cancelled — no PAT.");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const sel = extractSelector(target);
|
|
127
|
+
const rect = target.getBoundingClientRect();
|
|
128
|
+
const viewport = {
|
|
129
|
+
width: window.innerWidth,
|
|
130
|
+
height: window.innerHeight,
|
|
131
|
+
colorScheme: window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
132
|
+
? "dark"
|
|
133
|
+
: "light",
|
|
134
|
+
dpr: window.devicePixelRatio || 1,
|
|
135
|
+
};
|
|
136
|
+
const payload = buildPayload({
|
|
137
|
+
overlayVersion,
|
|
138
|
+
storyId,
|
|
139
|
+
url: window.location.href,
|
|
140
|
+
prose,
|
|
141
|
+
selector: sel,
|
|
142
|
+
bbox: { x: rect.x, y: rect.y, w: rect.width, h: rect.height },
|
|
143
|
+
viewport,
|
|
144
|
+
userAgent: navigator.userAgent,
|
|
145
|
+
});
|
|
146
|
+
const body = formatReviewComment({ payload });
|
|
147
|
+
const result = await submitComment({
|
|
148
|
+
owner: repoCoord.owner,
|
|
149
|
+
repo: repoCoord.repo,
|
|
150
|
+
pr: prNumber,
|
|
151
|
+
pat,
|
|
152
|
+
body,
|
|
153
|
+
});
|
|
154
|
+
if (result.ok) {
|
|
155
|
+
setFeedback(`Comment posted (#${result.commentId}).`);
|
|
156
|
+
setComposerOpen(false);
|
|
157
|
+
setTarget(null);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
setFeedback(`Failed: ${result.status} ${result.message}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
setSubmitting(false);
|
|
165
|
+
}
|
|
166
|
+
}, [overlayVersion, prNumber, repoCoord, storyId, target]);
|
|
167
|
+
if (!enabled)
|
|
168
|
+
return null;
|
|
169
|
+
if (typeof window === "undefined")
|
|
170
|
+
return null;
|
|
171
|
+
return (_jsxs("div", { "data-slowcook-overlay-ui": "1", style: {
|
|
172
|
+
position: "fixed",
|
|
173
|
+
inset: 0,
|
|
174
|
+
pointerEvents: "none",
|
|
175
|
+
zIndex: 2147483000,
|
|
176
|
+
}, children: [mode !== "nav" && (_jsx("div", { style: {
|
|
177
|
+
position: "absolute",
|
|
178
|
+
inset: 0,
|
|
179
|
+
backgroundColor: mode === "comment"
|
|
180
|
+
? "rgba(255, 107, 107, 0.05)"
|
|
181
|
+
: "rgba(74, 222, 128, 0.05)",
|
|
182
|
+
pointerEvents: "none",
|
|
183
|
+
}, "aria-hidden": "true" })), _jsx(ModeToggle, { mode: mode, onChange: setMode, disabled: submitting }), composerOpen && target && (_jsx(Composer, { target: target, onCancel: () => {
|
|
184
|
+
setComposerOpen(false);
|
|
185
|
+
setTarget(null);
|
|
186
|
+
}, onSubmit: submitFromComposer, submitting: submitting, composerRef: composerRef })), feedback && _jsx(FeedbackToast, { text: feedback, onDismiss: () => setFeedback(null) })] }));
|
|
187
|
+
}
|
|
188
|
+
function ModeToggle(props) {
|
|
189
|
+
const { mode, onChange, disabled } = props;
|
|
190
|
+
return (_jsxs("div", { "data-slowcook-overlay-ui": "1", style: {
|
|
191
|
+
position: "absolute",
|
|
192
|
+
top: 12,
|
|
193
|
+
right: 12,
|
|
194
|
+
pointerEvents: "auto",
|
|
195
|
+
display: "flex",
|
|
196
|
+
gap: 4,
|
|
197
|
+
background: "rgba(15, 15, 24, 0.92)",
|
|
198
|
+
padding: 4,
|
|
199
|
+
borderRadius: 999,
|
|
200
|
+
boxShadow: "0 4px 14px rgba(0,0,0,0.25)",
|
|
201
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
202
|
+
fontSize: 13,
|
|
203
|
+
color: "white",
|
|
204
|
+
}, children: [_jsx(ToggleButton, { active: mode === "nav", onClick: () => onChange("nav"), disabled: disabled, label: "Nav" }), _jsx(ToggleButton, { active: mode === "comment", onClick: () => onChange("comment"), disabled: disabled, label: "\uD83D\uDCAC Comment", accent: true }), _jsx(ToggleButton, { active: mode === "approve", onClick: () => onChange("approve"), disabled: disabled, label: "\u2705 Approve", approve: true })] }));
|
|
205
|
+
}
|
|
206
|
+
function ToggleButton(props) {
|
|
207
|
+
const bg = props.active
|
|
208
|
+
? props.approve
|
|
209
|
+
? "#22c55e"
|
|
210
|
+
: props.accent
|
|
211
|
+
? ACCENT
|
|
212
|
+
: "rgba(255,255,255,0.18)"
|
|
213
|
+
: "transparent";
|
|
214
|
+
return (_jsx("button", { type: "button", onClick: props.onClick, disabled: props.disabled, style: {
|
|
215
|
+
background: bg,
|
|
216
|
+
color: "white",
|
|
217
|
+
border: "none",
|
|
218
|
+
padding: "6px 12px",
|
|
219
|
+
borderRadius: 999,
|
|
220
|
+
cursor: props.disabled ? "not-allowed" : "pointer",
|
|
221
|
+
opacity: props.disabled ? 0.6 : 1,
|
|
222
|
+
font: "inherit",
|
|
223
|
+
}, children: props.label }));
|
|
224
|
+
}
|
|
225
|
+
function Composer(props) {
|
|
226
|
+
const [prose, setProse] = useState("");
|
|
227
|
+
const sel = extractSelector(props.target);
|
|
228
|
+
const rect = props.target.getBoundingClientRect();
|
|
229
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { style: {
|
|
230
|
+
position: "absolute",
|
|
231
|
+
left: rect.x,
|
|
232
|
+
top: rect.y,
|
|
233
|
+
width: rect.width,
|
|
234
|
+
height: rect.height,
|
|
235
|
+
border: `2px solid ${ACCENT}`,
|
|
236
|
+
outlineOffset: -2,
|
|
237
|
+
pointerEvents: "none",
|
|
238
|
+
}, "aria-hidden": "true" }), _jsxs("div", { ref: props.composerRef, "data-slowcook-overlay-ui": "1", role: "dialog", "aria-label": "Review comment", style: {
|
|
239
|
+
position: "absolute",
|
|
240
|
+
right: 12,
|
|
241
|
+
top: 64,
|
|
242
|
+
width: 320,
|
|
243
|
+
maxHeight: "70vh",
|
|
244
|
+
overflow: "auto",
|
|
245
|
+
background: "white",
|
|
246
|
+
color: "#1a1a1a",
|
|
247
|
+
borderRadius: 8,
|
|
248
|
+
boxShadow: "0 12px 40px rgba(0,0,0,0.3)",
|
|
249
|
+
padding: 16,
|
|
250
|
+
pointerEvents: "auto",
|
|
251
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
252
|
+
fontSize: 13,
|
|
253
|
+
}, children: [_jsx("div", { style: { fontWeight: 600, marginBottom: 8 }, children: "Review comment" }), _jsx("div", { style: { fontFamily: "ui-monospace, SFMono-Regular, monospace", fontSize: 11, opacity: 0.7, marginBottom: 8, wordBreak: "break-all" }, children: sel.selector }), _jsx("textarea", { "aria-label": "Comment text", autoFocus: true, value: prose, onChange: (e) => setProse(e.target.value), placeholder: "What's off about this element?", rows: 5, style: {
|
|
254
|
+
width: "100%",
|
|
255
|
+
padding: 8,
|
|
256
|
+
border: "1px solid rgba(0,0,0,0.15)",
|
|
257
|
+
borderRadius: 6,
|
|
258
|
+
font: "inherit",
|
|
259
|
+
resize: "vertical",
|
|
260
|
+
boxSizing: "border-box",
|
|
261
|
+
} }), _jsxs("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }, children: [_jsx("button", { type: "button", onClick: props.onCancel, disabled: props.submitting, style: {
|
|
262
|
+
background: "transparent",
|
|
263
|
+
border: "1px solid rgba(0,0,0,0.15)",
|
|
264
|
+
padding: "6px 12px",
|
|
265
|
+
borderRadius: 6,
|
|
266
|
+
cursor: "pointer",
|
|
267
|
+
font: "inherit",
|
|
268
|
+
}, children: "Cancel" }), _jsx("button", { type: "button", disabled: props.submitting || prose.trim() === "", onClick: () => void props.onSubmit(prose.trim()), style: {
|
|
269
|
+
background: ACCENT,
|
|
270
|
+
color: "white",
|
|
271
|
+
border: "none",
|
|
272
|
+
padding: "6px 14px",
|
|
273
|
+
borderRadius: 6,
|
|
274
|
+
cursor: props.submitting ? "not-allowed" : "pointer",
|
|
275
|
+
opacity: props.submitting || prose.trim() === "" ? 0.6 : 1,
|
|
276
|
+
font: "inherit",
|
|
277
|
+
fontWeight: 600,
|
|
278
|
+
}, children: props.submitting ? "Submitting…" : "Submit" })] })] })] }));
|
|
279
|
+
}
|
|
280
|
+
function FeedbackToast(props) {
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
const t = setTimeout(props.onDismiss, 4000);
|
|
283
|
+
return () => clearTimeout(t);
|
|
284
|
+
}, [props]);
|
|
285
|
+
return (_jsx("div", { "data-slowcook-overlay-ui": "1", style: {
|
|
286
|
+
position: "absolute",
|
|
287
|
+
bottom: 24,
|
|
288
|
+
right: 24,
|
|
289
|
+
background: "rgba(15, 15, 24, 0.92)",
|
|
290
|
+
color: "white",
|
|
291
|
+
padding: "10px 16px",
|
|
292
|
+
borderRadius: 8,
|
|
293
|
+
boxShadow: "0 4px 14px rgba(0,0,0,0.3)",
|
|
294
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
295
|
+
fontSize: 13,
|
|
296
|
+
pointerEvents: "auto",
|
|
297
|
+
maxWidth: 320,
|
|
298
|
+
}, role: "status", children: props.text }));
|
|
299
|
+
}
|
|
300
|
+
function ensurePat(repo) {
|
|
301
|
+
// Try localStorage first; fall back to a window.prompt() the first
|
|
302
|
+
// time. The PAT scopes the consumer needs are public_repo (or repo
|
|
303
|
+
// for private). Storing in localStorage keeps it scoped to the
|
|
304
|
+
// preview origin.
|
|
305
|
+
if (typeof window === "undefined")
|
|
306
|
+
return null;
|
|
307
|
+
let pat = loadPat(window.localStorage, repo);
|
|
308
|
+
if (pat)
|
|
309
|
+
return pat;
|
|
310
|
+
const entered = window.prompt(`Slowcook needs a GitHub PAT (scope: public_repo or repo) to post a comment on ${repo.owner}/${repo.repo}.\n\nIt will be stored only in this browser's localStorage for ${repo.owner}/${repo.repo}.`);
|
|
311
|
+
if (!entered || entered.trim() === "")
|
|
312
|
+
return null;
|
|
313
|
+
pat = entered.trim();
|
|
314
|
+
savePat(window.localStorage, repo, pat);
|
|
315
|
+
return pat;
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../src/react/overlay.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element selector extraction — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* Walks an element's attributes + ancestry to produce a stable selector
|
|
5
|
+
* that plate (and humans) can use to find the element later. Priority
|
|
6
|
+
* matches the 0.13.1-review-overlay design:
|
|
7
|
+
*
|
|
8
|
+
* 1. id → `#unread-badge` (most stable)
|
|
9
|
+
* 2. data-testid → `[data-testid="unread-badge"]`
|
|
10
|
+
* 3. role + name → `button[aria-label="Sign in"]`
|
|
11
|
+
* 4. tag.classes → `span.badge.bg-mint:nth-child(2)`
|
|
12
|
+
* 5. XPath → `/html/body/div/span[2]` (last resort)
|
|
13
|
+
*
|
|
14
|
+
* Each strategy returns null when not applicable; `extractSelector`
|
|
15
|
+
* tries them in order and returns the first hit. The selector is
|
|
16
|
+
* always non-empty for a real DOM element.
|
|
17
|
+
*
|
|
18
|
+
* Pure functions; no DOM globals beyond what each function takes as
|
|
19
|
+
* input. Testable in node + jsdom.
|
|
20
|
+
*/
|
|
21
|
+
export interface ExtractedSelector {
|
|
22
|
+
/** Best stable selector. Always populated. */
|
|
23
|
+
selector: string;
|
|
24
|
+
/** Lower-priority fallback (one rung down the priority list). */
|
|
25
|
+
fallbackSelector: string | null;
|
|
26
|
+
/** Strategy that produced `selector`. */
|
|
27
|
+
strategy: "id" | "data-testid" | "role-name" | "tag-classes" | "xpath";
|
|
28
|
+
/** Raw element tag (lowercased). */
|
|
29
|
+
tag: string;
|
|
30
|
+
/** First 80 chars of trimmed text content; null when empty. */
|
|
31
|
+
textHint: string | null;
|
|
32
|
+
}
|
|
33
|
+
export declare function extractSelector(el: Element): ExtractedSelector;
|
|
34
|
+
//# sourceMappingURL=selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../src/selector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,yCAAyC;IACzC,QAAQ,EAAE,IAAI,GAAG,aAAa,GAAG,WAAW,GAAG,aAAa,GAAG,OAAO,CAAC;IACvE,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,OAAO,GAAG,iBAAiB,CA6C9D"}
|
package/dist/selector.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element selector extraction — 0.16.0-α.6.
|
|
3
|
+
*
|
|
4
|
+
* Walks an element's attributes + ancestry to produce a stable selector
|
|
5
|
+
* that plate (and humans) can use to find the element later. Priority
|
|
6
|
+
* matches the 0.13.1-review-overlay design:
|
|
7
|
+
*
|
|
8
|
+
* 1. id → `#unread-badge` (most stable)
|
|
9
|
+
* 2. data-testid → `[data-testid="unread-badge"]`
|
|
10
|
+
* 3. role + name → `button[aria-label="Sign in"]`
|
|
11
|
+
* 4. tag.classes → `span.badge.bg-mint:nth-child(2)`
|
|
12
|
+
* 5. XPath → `/html/body/div/span[2]` (last resort)
|
|
13
|
+
*
|
|
14
|
+
* Each strategy returns null when not applicable; `extractSelector`
|
|
15
|
+
* tries them in order and returns the first hit. The selector is
|
|
16
|
+
* always non-empty for a real DOM element.
|
|
17
|
+
*
|
|
18
|
+
* Pure functions; no DOM globals beyond what each function takes as
|
|
19
|
+
* input. Testable in node + jsdom.
|
|
20
|
+
*/
|
|
21
|
+
export function extractSelector(el) {
|
|
22
|
+
const tag = el.tagName.toLowerCase();
|
|
23
|
+
const textHint = textHintOf(el);
|
|
24
|
+
const ord = [
|
|
25
|
+
{ strategy: "id", sel: byId(el) },
|
|
26
|
+
{ strategy: "data-testid", sel: byTestId(el) },
|
|
27
|
+
{ strategy: "role-name", sel: byRoleName(el) },
|
|
28
|
+
{ strategy: "tag-classes", sel: byTagClasses(el) },
|
|
29
|
+
{ strategy: "xpath", sel: byXPath(el) },
|
|
30
|
+
];
|
|
31
|
+
let primary = null;
|
|
32
|
+
let fallback = null;
|
|
33
|
+
for (const o of ord) {
|
|
34
|
+
if (o.sel === null)
|
|
35
|
+
continue;
|
|
36
|
+
if (primary === null) {
|
|
37
|
+
primary = { strategy: o.strategy, sel: o.sel };
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
fallback = o.sel;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Real elements always produce at least an XPath; the null branch
|
|
45
|
+
// here is defensive and would only fire on a detached node.
|
|
46
|
+
if (primary === null) {
|
|
47
|
+
return {
|
|
48
|
+
selector: tag,
|
|
49
|
+
fallbackSelector: null,
|
|
50
|
+
strategy: "tag-classes",
|
|
51
|
+
tag,
|
|
52
|
+
textHint,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
selector: primary.sel,
|
|
57
|
+
fallbackSelector: fallback,
|
|
58
|
+
strategy: primary.strategy,
|
|
59
|
+
tag,
|
|
60
|
+
textHint,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function textHintOf(el) {
|
|
64
|
+
const t = (el.textContent ?? "").trim().replace(/\s+/g, " ");
|
|
65
|
+
if (!t)
|
|
66
|
+
return null;
|
|
67
|
+
return t.length > 80 ? t.slice(0, 77) + "…" : t;
|
|
68
|
+
}
|
|
69
|
+
function byId(el) {
|
|
70
|
+
const id = el.id;
|
|
71
|
+
if (!id)
|
|
72
|
+
return null;
|
|
73
|
+
// Skip auto-generated id patterns React + many UI libs produce.
|
|
74
|
+
if (/^:r[0-9a-z]+:$/.test(id))
|
|
75
|
+
return null; // React useId
|
|
76
|
+
if (/^radix-:r/.test(id))
|
|
77
|
+
return null; // Radix
|
|
78
|
+
if (/^headlessui-/.test(id))
|
|
79
|
+
return null; // Headless UI
|
|
80
|
+
return `#${cssEscapeIdent(id)}`;
|
|
81
|
+
}
|
|
82
|
+
function byTestId(el) {
|
|
83
|
+
const v = el.getAttribute("data-testid");
|
|
84
|
+
if (!v)
|
|
85
|
+
return null;
|
|
86
|
+
return `[data-testid="${cssEscapeAttr(v)}"]`;
|
|
87
|
+
}
|
|
88
|
+
function byRoleName(el) {
|
|
89
|
+
const role = el.getAttribute("role") ?? implicitRoleOf(el);
|
|
90
|
+
if (!role)
|
|
91
|
+
return null;
|
|
92
|
+
const name = accessibleNameOf(el);
|
|
93
|
+
if (!name)
|
|
94
|
+
return null;
|
|
95
|
+
return `${el.tagName.toLowerCase()}[aria-label="${cssEscapeAttr(name)}"]`;
|
|
96
|
+
}
|
|
97
|
+
function byTagClasses(el) {
|
|
98
|
+
const classes = Array.from(el.classList).filter((c) => isMeaningfulClass(c));
|
|
99
|
+
if (classes.length === 0)
|
|
100
|
+
return null;
|
|
101
|
+
const head = classes.slice(0, 2).map(cssEscapeIdent).join(".");
|
|
102
|
+
// Add nth-child for structural disambiguation when the parent has
|
|
103
|
+
// more than one child of the same tag — common case.
|
|
104
|
+
const parent = el.parentElement;
|
|
105
|
+
let suffix = "";
|
|
106
|
+
if (parent) {
|
|
107
|
+
const sameTag = Array.from(parent.children).filter((c) => c.tagName === el.tagName);
|
|
108
|
+
if (sameTag.length > 1) {
|
|
109
|
+
const idx = Array.from(parent.children).indexOf(el) + 1;
|
|
110
|
+
suffix = `:nth-child(${idx})`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return `${el.tagName.toLowerCase()}.${head}${suffix}`;
|
|
114
|
+
}
|
|
115
|
+
function byXPath(el) {
|
|
116
|
+
const parts = [];
|
|
117
|
+
let node = el;
|
|
118
|
+
while (node && node.nodeType === 1 && node.tagName.toLowerCase() !== "html") {
|
|
119
|
+
const parent = node.parentElement;
|
|
120
|
+
if (!parent)
|
|
121
|
+
break;
|
|
122
|
+
const tag = node.tagName.toLowerCase();
|
|
123
|
+
const sameTag = Array.from(parent.children).filter((c) => c.tagName === node.tagName);
|
|
124
|
+
const idx = sameTag.indexOf(node) + 1;
|
|
125
|
+
parts.unshift(sameTag.length > 1 ? `${tag}[${idx}]` : tag);
|
|
126
|
+
node = parent;
|
|
127
|
+
}
|
|
128
|
+
return "/html/body/" + parts.join("/");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Implicit roles for the most common elements. Not a complete ARIA map
|
|
132
|
+
* — extends as needed. Matches the most common review-target tags.
|
|
133
|
+
*/
|
|
134
|
+
function implicitRoleOf(el) {
|
|
135
|
+
const tag = el.tagName.toLowerCase();
|
|
136
|
+
switch (tag) {
|
|
137
|
+
case "button": return "button";
|
|
138
|
+
case "a": return el.hasAttribute("href") ? "link" : null;
|
|
139
|
+
case "nav": return "navigation";
|
|
140
|
+
case "main": return "main";
|
|
141
|
+
case "header": return "banner";
|
|
142
|
+
case "footer": return "contentinfo";
|
|
143
|
+
case "h1":
|
|
144
|
+
case "h2":
|
|
145
|
+
case "h3":
|
|
146
|
+
case "h4":
|
|
147
|
+
case "h5":
|
|
148
|
+
case "h6": return "heading";
|
|
149
|
+
case "img": return "img";
|
|
150
|
+
case "input": {
|
|
151
|
+
const type = (el.getAttribute("type") ?? "text").toLowerCase();
|
|
152
|
+
if (type === "checkbox")
|
|
153
|
+
return "checkbox";
|
|
154
|
+
if (type === "radio")
|
|
155
|
+
return "radio";
|
|
156
|
+
if (type === "submit" || type === "button")
|
|
157
|
+
return "button";
|
|
158
|
+
return "textbox";
|
|
159
|
+
}
|
|
160
|
+
default: return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function accessibleNameOf(el) {
|
|
164
|
+
// Order: aria-label > aria-labelledby's text > <label for> match >
|
|
165
|
+
// textContent (for buttons / links).
|
|
166
|
+
const ariaLabel = el.getAttribute("aria-label");
|
|
167
|
+
if (ariaLabel)
|
|
168
|
+
return ariaLabel.trim() || null;
|
|
169
|
+
const labelledBy = el.getAttribute("aria-labelledby");
|
|
170
|
+
if (labelledBy && el.ownerDocument) {
|
|
171
|
+
const ids = labelledBy.split(/\s+/);
|
|
172
|
+
const parts = [];
|
|
173
|
+
for (const id of ids) {
|
|
174
|
+
const ref = el.ownerDocument.getElementById(id);
|
|
175
|
+
if (ref)
|
|
176
|
+
parts.push((ref.textContent ?? "").trim());
|
|
177
|
+
}
|
|
178
|
+
if (parts.join(" ").trim())
|
|
179
|
+
return parts.join(" ").trim();
|
|
180
|
+
}
|
|
181
|
+
// For form controls, look up associated <label>
|
|
182
|
+
if (el.id && el.ownerDocument) {
|
|
183
|
+
const label = el.ownerDocument.querySelector(`label[for="${cssEscapeAttr(el.id)}"]`);
|
|
184
|
+
if (label) {
|
|
185
|
+
const t = (label.textContent ?? "").trim();
|
|
186
|
+
if (t)
|
|
187
|
+
return t;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// For buttons + links, textContent is the accessible name
|
|
191
|
+
const tag = el.tagName.toLowerCase();
|
|
192
|
+
if (tag === "button" || tag === "a") {
|
|
193
|
+
const t = (el.textContent ?? "").trim().replace(/\s+/g, " ");
|
|
194
|
+
if (t)
|
|
195
|
+
return t.length > 60 ? t.slice(0, 57) + "…" : t;
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Skip Tailwind utility classes, framework-injected classes, and other
|
|
201
|
+
* volatile-looking class names when picking the seed for tag.classes.
|
|
202
|
+
*
|
|
203
|
+
* These rules are heuristic — false positives only cost selector
|
|
204
|
+
* specificity, not correctness; the XPath fallback always works.
|
|
205
|
+
*/
|
|
206
|
+
function isMeaningfulClass(c) {
|
|
207
|
+
if (!c)
|
|
208
|
+
return false;
|
|
209
|
+
// Tailwind utilities: bg-*, text-*, p-*, m-*, w-*, h-*, flex,
|
|
210
|
+
// grid, items-*, justify-*, hover:*, sm:*, dark:* etc.
|
|
211
|
+
if (/^(bg|text|p|m|w|h|gap|space|border|rounded|font|leading|tracking|opacity|shadow|ring|grid|flex|items|justify|self|content|order|col|row|min|max|inset|top|right|bottom|left|z|object|overflow|cursor|select|pointer|filter|backdrop|transition|duration|ease|delay|animate|origin|rotate|scale|translate|skew)-/.test(c))
|
|
212
|
+
return false;
|
|
213
|
+
if (/^(flex|grid|block|inline|hidden|absolute|relative|fixed|static|sticky|truncate|antialiased|italic|underline|uppercase|lowercase|capitalize)$/.test(c))
|
|
214
|
+
return false;
|
|
215
|
+
if (/^(hover|focus|active|disabled|sm|md|lg|xl|2xl|dark):/.test(c))
|
|
216
|
+
return false;
|
|
217
|
+
// CSS modules / styled-components / emotion hashes
|
|
218
|
+
if (/^[a-zA-Z]+__[a-zA-Z]+_/.test(c))
|
|
219
|
+
return false; // foo__bar_HASH
|
|
220
|
+
if (/^css-[a-zA-Z0-9]{4,}$/.test(c))
|
|
221
|
+
return false; // emotion css-XXXX
|
|
222
|
+
if (/^_[a-zA-Z0-9]{6,}$/.test(c))
|
|
223
|
+
return false; // module-hashed _XXXX
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
function cssEscapeIdent(s) {
|
|
227
|
+
// Lightweight CSS.escape replacement for ident contexts. Keeps
|
|
228
|
+
// alnum + hyphen + underscore; backslash-escapes anything else.
|
|
229
|
+
return s.replace(/[^a-zA-Z0-9_-]/g, (ch) => "\\" + ch);
|
|
230
|
+
}
|
|
231
|
+
function cssEscapeAttr(s) {
|
|
232
|
+
// Inside double-quoted attribute values: escape backslash + quote.
|
|
233
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.js","sourceRoot":"","sources":["../src/selector.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@slowcook-ai/review-overlay",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Floating review overlay for slowcook mock previews — element-anchored comments, screenshot, viewport metadata; submits to the mockup PR via PAT. Mounted into the mock app's root layout. Plate parses the comments back out for amendments.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "aminazar",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/aminazar/slowcook.git",
|
|
10
|
+
"directory": "packages/review-overlay"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/aminazar/slowcook/tree/main/packages/review-overlay#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/aminazar/slowcook/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"slowcook",
|
|
18
|
+
"review",
|
|
19
|
+
"overlay",
|
|
20
|
+
"mock",
|
|
21
|
+
"annotations",
|
|
22
|
+
"react"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./react": {
|
|
33
|
+
"types": "./dist/react/index.d.ts",
|
|
34
|
+
"import": "./dist/react/index.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md"
|
|
40
|
+
],
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"react": ">=19",
|
|
43
|
+
"react-dom": ">=19"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"react": "^19.0.0",
|
|
47
|
+
"react-dom": "^19.0.0",
|
|
48
|
+
"@types/react": "^19.0.0",
|
|
49
|
+
"jsdom": "^25.0.0"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc -b",
|
|
59
|
+
"test": "vitest run --passWithNoTests",
|
|
60
|
+
"typecheck": "tsc --noEmit"
|
|
61
|
+
}
|
|
62
|
+
}
|