@slowcook-ai/review-overlay 0.10.0 → 0.12.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/index.d.ts CHANGED
@@ -11,6 +11,6 @@
11
11
  * decode review comments off the PR thread.
12
12
  */
13
13
  export { PAYLOAD_MARKER, PLATE_REPLY_MARKER, formatReviewComment, parseReviewComment, formatPlateReplyBlock, parsePlateReply, buildPayload, type ReviewCommentPayload, type ViewportInfo, type FormatArgs, type PlateReplyEntry, type PlateReplyPayload, type PlateReplyStatus, } from "./comment-format.js";
14
- export { extractSelector, resolveStoredSelector, resolveAnchor, extractA11yPath, resolveA11yPath, roleOf, type ExtractedSelector, type A11yPath, type A11ySeg, } from "./selector.js";
14
+ export { extractSelector, resolveStoredSelector, resolveAnchor, extractA11yPath, resolveA11yPath, roleOf, isPillOffViewport, clampPillPosition, type ExtractedSelector, type A11yPath, type A11ySeg, } from "./selector.js";
15
15
  export { loadPat, savePat, clearPat, patStorageKey, submitComment, fetchOverlayComments, loadCachedComments, saveCachedComments, commentsCacheKey, fetchAllMockupPrs, fetchScenarioStats, loadCachedScenarioStats, saveCachedScenarioStats, scenarioStatsCacheKey, emptyStats, fetchPrLabels, addLabelsToPr, submitPrApproval, APPROVED_LABEL, type RepoCoord, type SubmitArgs, type SubmitResult, type SubmitOk, type SubmitErr, type OverlayCommentRecord, type ScenarioCommentStats, } from "./github.js";
16
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,eAAe,EACf,eAAe,EACf,MAAM,EACN,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,OAAO,GACb,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,OAAO,EACP,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,eAAe,EACf,eAAe,EACf,MAAM,EACN,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,OAAO,GACb,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,OAAO,EACP,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -11,6 +11,6 @@
11
11
  * decode review comments off the PR thread.
12
12
  */
13
13
  export { PAYLOAD_MARKER, PLATE_REPLY_MARKER, formatReviewComment, parseReviewComment, formatPlateReplyBlock, parsePlateReply, buildPayload, } from "./comment-format.js";
14
- export { extractSelector, resolveStoredSelector, resolveAnchor, extractA11yPath, resolveA11yPath, roleOf, } from "./selector.js";
14
+ export { extractSelector, resolveStoredSelector, resolveAnchor, extractA11yPath, resolveA11yPath, roleOf, isPillOffViewport, clampPillPosition, } from "./selector.js";
15
15
  export { loadPat, savePat, clearPat, patStorageKey, submitComment, fetchOverlayComments, loadCachedComments, saveCachedComments, commentsCacheKey, fetchAllMockupPrs, fetchScenarioStats, loadCachedScenarioStats, saveCachedScenarioStats, scenarioStatsCacheKey, emptyStats, fetchPrLabels, addLabelsToPr, submitPrApproval, APPROVED_LABEL, } from "./github.js";
16
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,GAOb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,eAAe,EACf,eAAe,EACf,MAAM,GAIP,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,OAAO,EACP,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,cAAc,GAQf,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,GAOb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,eAAe,EACf,eAAe,EACf,MAAM,EACN,iBAAiB,EACjB,iBAAiB,GAIlB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,OAAO,EACP,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,UAAU,EACV,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,cAAc,GAQf,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { ReviewShell, localStorageStore, type ReviewShellProps, type ReviewComment, type ReviewCommentMeta, type CommentStore, type Corner, } from "./react/review-shell.js";
2
+ export { usePrefersDark, detectPageDark, pillTheme, sheetTheme } from "./react/theme.js";
3
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,MAAM,GACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,8 @@
1
+ // ── @slowcook-ai/review-overlay/primitives ──────────────────────────────────
2
+ // The SHELL PRIMITIVES: generic, workflow-free review-surface building blocks.
3
+ // OSS-specific shells (the vibe/plate LCR overlay, the Refine ReviewWidget)
4
+ // and external consumers (dash's RefinePill → pm-/brand-assistant loop) build
5
+ // on these. Nothing here knows about GitHub, PRs, stories, or agents.
6
+ export { ReviewShell, localStorageStore, } from "./react/review-shell.js";
7
+ export { usePrefersDark, detectPageDark, pillTheme, sheetTheme } from "./react/theme.js";
8
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,sEAAsE;AACtE,OAAO,EACL,WAAW,EACX,iBAAiB,GAMlB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { type RefObject, type JSX } from "react";
2
+ export interface CometLight {
3
+ /** viewport-space position of the (unseen) light, px. */
4
+ x: number;
5
+ y: number;
6
+ /** 0→1→0 intensity envelope over the comet's flight. */
7
+ alpha: number;
8
+ /** the light's colour as an "r,g,b" triplet — usually slowcook coral. */
9
+ rgb: string;
10
+ }
11
+ type Sub = (l: CometLight | null) => void;
12
+ /** Subscribe to the shared comet light. The driver runs only while ≥1 subscriber. */
13
+ export declare function subscribeComet(cb: Sub): () => void;
14
+ export declare function useCometLight(): CometLight | null;
15
+ /** The reflection an element shows for a given light position — a moving sheen
16
+ * whose hotspot tracks the light, fading with distance, plus a border glint. */
17
+ export declare function cometReflection(light: CometLight | null, rect: DOMRect | null): {
18
+ background: string;
19
+ boxShadow: string;
20
+ opacity: number;
21
+ };
22
+ /** Overlay that renders the comet reflection for the pill it's mounted into. It
23
+ * subscribes to the light itself, so only THIS node re-renders per frame — the
24
+ * parent pill stays put. Mount as an absolute, inset child of the pill. */
25
+ export declare function CometSheen({ pillRef, radius }: {
26
+ pillRef: RefObject<HTMLElement | null>;
27
+ radius: number | string;
28
+ }): JSX.Element;
29
+ export {};
30
+ //# sourceMappingURL=comet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comet.d.ts","sourceRoot":"","sources":["../../src/react/comet.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAmD,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAElG,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;CACb;AAQD,KAAK,GAAG,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;AAqE1C,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,EAAE,EAAE,GAAG,GAAG,MAAM,IAAI,CAQlD;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAIjD;AAED;iFACiF;AACjF,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAuB1I;AAED;;4EAE4E;AAC5E,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;IAAE,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GAAG,GAAG,CAAC,OAAO,CAoBhI"}
@@ -0,0 +1,151 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // A shared "comet light" — an INVISIBLE point of light that, every now and then,
3
+ // streaks across the viewport. You never see the comet itself; you only see its
4
+ // reflection glint across the floating review pills as it passes near them (their
5
+ // background catches the sheen and their borders briefly shine). One driver, many
6
+ // subscribers, so the overlay pill and the Refine pill reflect the SAME comet in
7
+ // sync. Honors prefers-reduced-motion (no comets) and only runs while subscribed.
8
+ import { useEffect, useRef, useState } from "react";
9
+ // The comet's light is USUALLY slowcook coral; once in a while a warm white or a
10
+ // gold streak for variety.
11
+ const CORAL = "255,107,107";
12
+ const COMET_COLORS = [CORAL, CORAL, CORAL, CORAL, "255,224,205", "255,196,120"];
13
+ const pickColor = () => COMET_COLORS[Math.floor(Math.random() * COMET_COLORS.length)];
14
+ const subs = new Set();
15
+ let current = null;
16
+ let raf = 0;
17
+ let timer = 0;
18
+ let started = false;
19
+ const reduced = () => typeof window !== "undefined" &&
20
+ typeof window.matchMedia === "function" &&
21
+ window.matchMedia("(prefers-reduced-motion: reduce)").matches;
22
+ function emit(l) {
23
+ current = l;
24
+ for (const s of subs)
25
+ s(l);
26
+ }
27
+ // A point a little outside a random edge of the viewport.
28
+ function edgePoint(W, H) {
29
+ const pad = 120;
30
+ switch (Math.floor(Math.random() * 4)) {
31
+ case 0: return { x: Math.random() * W, y: -pad }; // top
32
+ case 1: return { x: W + pad, y: Math.random() * H }; // right
33
+ case 2: return { x: Math.random() * W, y: H + pad }; // bottom
34
+ default: return { x: -pad, y: Math.random() * H }; // left
35
+ }
36
+ }
37
+ function launch() {
38
+ if (typeof window === "undefined")
39
+ return;
40
+ const W = window.innerWidth, H = window.innerHeight;
41
+ // Random direction + path: random entry edge → random exit, re-rolled only if the
42
+ // streak would be too short to actually cross anything.
43
+ const start = edgePoint(W, H);
44
+ let end = edgePoint(W, H);
45
+ for (let i = 0; i < 4 && Math.hypot(end.x - start.x, end.y - start.y) < Math.max(W, H) * 0.5; i++)
46
+ end = edgePoint(W, H);
47
+ const rgb = pickColor();
48
+ const dur = 2200 + Math.random() * 1300; // 2.2–3.5s flight
49
+ const t0 = performance.now();
50
+ const step = (now) => {
51
+ const p = (now - t0) / dur;
52
+ if (p >= 1) {
53
+ emit(null);
54
+ schedule();
55
+ return;
56
+ }
57
+ emit({
58
+ x: start.x + (end.x - start.x) * p,
59
+ y: start.y + (end.y - start.y) * p,
60
+ alpha: Math.sin(Math.PI * p), // fade in to the middle, fade out
61
+ rgb,
62
+ });
63
+ raf = requestAnimationFrame(step);
64
+ };
65
+ raf = requestAnimationFrame(step);
66
+ }
67
+ function schedule() {
68
+ timer = window.setTimeout(launch, 3500 + Math.random() * 6000); // a comet every ~3.5–9.5s
69
+ }
70
+ function startDriver() {
71
+ if (started || reduced() || typeof window === "undefined")
72
+ return;
73
+ started = true;
74
+ schedule();
75
+ }
76
+ function stopDriver() {
77
+ started = false;
78
+ clearTimeout(timer);
79
+ cancelAnimationFrame(raf);
80
+ emit(null);
81
+ }
82
+ /** Subscribe to the shared comet light. The driver runs only while ≥1 subscriber. */
83
+ export function subscribeComet(cb) {
84
+ subs.add(cb);
85
+ if (subs.size === 1)
86
+ startDriver();
87
+ cb(current);
88
+ return () => {
89
+ subs.delete(cb);
90
+ if (subs.size === 0)
91
+ stopDriver();
92
+ };
93
+ }
94
+ export function useCometLight() {
95
+ const [l, setL] = useState(current);
96
+ useEffect(() => subscribeComet(setL), []);
97
+ return l;
98
+ }
99
+ /** The reflection an element shows for a given light position — a moving sheen
100
+ * whose hotspot tracks the light, fading with distance, plus a border glint. */
101
+ export function cometReflection(light, rect) {
102
+ const none = { background: "transparent", boxShadow: "none", opacity: 0 };
103
+ if (!light || !rect)
104
+ return none;
105
+ const cx = rect.left + rect.width / 2, cy = rect.top + rect.height / 2;
106
+ const dist = Math.hypot(light.x - cx, light.y - cy);
107
+ const reach = 720; // pills within this radius catch the passing light
108
+ const prox = Math.max(0, 1 - dist / reach);
109
+ // gentle (sub-quadratic) falloff so near-misses still glint clearly; proximity
110
+ // dominates, the flight envelope only modulates, so a close pass is always bright.
111
+ const k = Math.pow(prox, 1.25) * (0.5 + 0.5 * light.alpha);
112
+ if (k <= 0.008)
113
+ return none;
114
+ const c = light.rgb; // usually slowcook coral
115
+ const lx = light.x - rect.left, ly = light.y - rect.top; // hotspot in pill-local px
116
+ // a hot white core fading to coral reads as a bright reflection sweeping the pill.
117
+ const background = `radial-gradient(210px 210px at ${lx.toFixed(0)}px ${ly.toFixed(0)}px,` +
118
+ ` rgba(255,255,255,${Math.min(1, 1.0 * k).toFixed(3)}), rgba(${c},${Math.min(1, 1.05 * k).toFixed(3)}) 30%, rgba(${c},0) 68%)`;
119
+ // the border catches the light: a bright coral ring where the light is, plus a
120
+ // wide outer glow so the whole pill flares as the comet passes.
121
+ const boxShadow = `inset 0 0 0 1.5px rgba(${c},${Math.min(1, 1.2 * k).toFixed(3)}),` +
122
+ ` 0 0 ${(14 + 40 * k).toFixed(0)}px rgba(${c},${Math.min(0.85, 0.7 * k).toFixed(3)})`;
123
+ return { background, boxShadow, opacity: 1 };
124
+ }
125
+ /** Overlay that renders the comet reflection for the pill it's mounted into. It
126
+ * subscribes to the light itself, so only THIS node re-renders per frame — the
127
+ * parent pill stays put. Mount as an absolute, inset child of the pill. */
128
+ export function CometSheen({ pillRef, radius }) {
129
+ const light = useCometLight();
130
+ const rectRef = useRef(null);
131
+ // measure once per comet (the pill rarely moves during a ~3s flight).
132
+ if (light && pillRef.current && !rectRef.current)
133
+ rectRef.current = pillRef.current.getBoundingClientRect();
134
+ if (!light)
135
+ rectRef.current = null;
136
+ const r = cometReflection(light, rectRef.current);
137
+ const style = {
138
+ position: "absolute",
139
+ inset: 0,
140
+ borderRadius: radius,
141
+ pointerEvents: "none",
142
+ background: r.background,
143
+ boxShadow: r.boxShadow,
144
+ opacity: r.opacity,
145
+ mixBlendMode: "screen",
146
+ zIndex: 9,
147
+ transition: "opacity .25s ease",
148
+ };
149
+ return _jsx("div", { "aria-hidden": true, "data-comet-sheen": "", style: style });
150
+ }
151
+ //# sourceMappingURL=comet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comet.js","sourceRoot":"","sources":["../../src/react/comet.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export { SlowcookReviewOverlay, type SlowcookReviewOverlayProps } from "./overlay.js";
2
2
  export { ReviewWidget, type ReviewWidgetProps, type ReviewComment, type Corner } from "./review-widget.js";
3
+ export { ReviewShell, localStorageStore, type ReviewShellProps, type ReviewCommentMeta, type CommentStore } from "./review-shell.js";
3
4
  export { usePrefersDark, detectPageDark, pillTheme, sheetTheme } from "./theme.js";
4
5
  export { useScenarioCommentStats, type UseScenarioCommentStatsArgs } from "./use-scenario-comment-stats.js";
5
6
  export { useStoryMarker, readCurrentStory } from "./use-story-marker.js";
@@ -1 +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;AACtF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC3G,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAE,KAAK,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
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;AACtF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACrI,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAE,KAAK,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export { SlowcookReviewOverlay } from "./overlay.js";
2
2
  export { ReviewWidget } from "./review-widget.js";
3
+ export { ReviewShell, localStorageStore } from "./review-shell.js";
3
4
  export { usePrefersDark, detectPageDark, pillTheme, sheetTheme } from "./theme.js";
4
5
  export { useScenarioCommentStats } from "./use-scenario-comment-stats.js";
5
6
  export { useStoryMarker, readCurrentStory } from "./use-story-marker.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAmC,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,YAAY,EAA2D,MAAM,oBAAoB,CAAC;AAC3G,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAoC,MAAM,iCAAiC,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAmC,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,YAAY,EAA2D,MAAM,oBAAoB,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAoE,MAAM,mBAAmB,CAAC;AACrI,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAoC,MAAM,iCAAiC,CAAC;AAC5G,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/react/overlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAA4C,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAW3F,OAAO,EAeL,KAAK,SAAS,EAGf,MAAM,cAAc,CAAC;AAiCtB,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CA25B3F;AA4BD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAelH"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../src/react/overlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAA4C,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAY3F,OAAO,EAeL,KAAK,SAAS,EAGf,MAAM,cAAc,CAAC;AAiCtB,MAAM,WAAW,0BAA0B;IACzC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CA25B3F;AA4BD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAelH"}
@@ -25,7 +25,8 @@
25
25
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
26
26
  import { useEffect, useState, useRef, useCallback } from "react";
27
27
  import { createPortal } from "react-dom";
28
- import { extractSelector, resolveAnchor } from "../selector.js";
28
+ import { extractSelector, resolveAnchor, isPillOffViewport, clampPillPosition } from "../selector.js";
29
+ import { CometSheen } from "./comet.js";
29
30
  import { buildPayload, formatReviewComment, formatLcrIssue, } from "../comment-format.js";
30
31
  import { loadPat, savePat, submitComment, createIssue, fetchOverlayComments, fetchLcrIssues, loadCachedComments, saveCachedComments, fetchPrLabels, addLabelsToPr, submitPrApproval, fetchDocFile, commitDocFile, APPROVED_LABEL, } from "../github.js";
31
32
  import { renderMarkdown } from "./markdown.js";
@@ -1046,14 +1047,40 @@ function saveTogglePosition(p) {
1046
1047
  /* ignore quota / private-mode errors */
1047
1048
  }
1048
1049
  }
1050
+ // 0.10.1 — a persisted position can fall outside the viewport (the window was
1051
+ // resized smaller, or the pill was dragged to an edge). Because the pill is
1052
+ // fixed/absolute chrome, an off-screen position is UNREACHABLE — you can't scroll
1053
+ // to it. So whenever we restore or the window resizes, snap a stranded pill back
1054
+ // to the top-left where it's always grabbable. `margin` keeps a sliver on-screen so
1055
+ // a position that's merely flush to an edge still counts as visible.
1056
+ function ensureOnScreen(p) {
1057
+ if (typeof window === "undefined")
1058
+ return p;
1059
+ return isPillOffViewport(p.left, p.top, window.innerWidth, window.innerHeight) ? { top: 12, left: 12 } : p;
1060
+ }
1049
1061
  function ModeToggle(props) {
1050
1062
  const { mode, armed, onArm, onCancelArm, onChange, disabled, isMobile, isApproved, commentCount, newCount, onListClick, docsEnabled, onDocsClick, surfaces, surfaceManifest, onNavigate, reviewMode, identity, onSignIn, onSignOut, accessory } = props;
1051
1063
  // 0.5.1 — initialise with the default; load saved position from
1052
1064
  // localStorage AFTER mount. Eliminates a hydration mismatch where
1053
1065
  // SSR/first-client render disagreed on the position value.
1054
1066
  const [pos, setPos] = useState({ top: 12, left: 12 });
1055
- useEffect(() => { setPos(loadTogglePosition()); }, []);
1067
+ // Restore the saved position after mount (avoids an SSR hydration mismatch), but
1068
+ // never restore it off-screen — snap a stranded pill back into view (0.10.1).
1069
+ useEffect(() => { setPos(ensureOnScreen(loadTogglePosition())); }, []);
1070
+ // If the window resizes such that the pill ends up outside the viewport, bring it
1071
+ // back (a fixed pill can't be scrolled to).
1072
+ useEffect(() => {
1073
+ const onResize = () => setPos((p) => {
1074
+ const next = ensureOnScreen(p);
1075
+ if (next !== p)
1076
+ saveTogglePosition(next);
1077
+ return next;
1078
+ });
1079
+ window.addEventListener("resize", onResize);
1080
+ return () => window.removeEventListener("resize", onResize);
1081
+ }, []);
1056
1082
  const dragRef = useRef(null);
1083
+ const pillRef = useRef(null);
1057
1084
  // 0.9.0 — EPSS jump palette open state. The tappable status (right of the
1058
1085
  // pill) opens it; it lists matching states to jump to.
1059
1086
  const [paletteOpen, setPaletteOpen] = useState(false);
@@ -1097,11 +1124,10 @@ function ModeToggle(props) {
1097
1124
  e.preventDefault();
1098
1125
  const dx = e.clientX - dragRef.current.startX;
1099
1126
  const dy = e.clientY - dragRef.current.startY;
1100
- const newTop = Math.max(0, dragRef.current.startTop + dy);
1101
- // Allow a slightly-negative left so a clipped (grown-right) pill can be
1102
- // panned left to reveal its right side; the grip stays grabbable.
1103
- const newLeft = Math.max(-2000, dragRef.current.startLeft + dx);
1104
- setPos({ top: newTop, left: newLeft });
1127
+ // 0.10.1 clamp into the viewport while dragging so the grip can never be
1128
+ // pushed off-screen (it's left-anchored now, so a negative left hides it).
1129
+ const { left, top } = clampPillPosition(dragRef.current.startLeft + dx, dragRef.current.startTop + dy, window.innerWidth, window.innerHeight);
1130
+ setPos({ top, left });
1105
1131
  }, []);
1106
1132
  const onPointerUp = useCallback((e) => {
1107
1133
  if (!dragRef.current)
@@ -1110,7 +1136,7 @@ function ModeToggle(props) {
1110
1136
  dragRef.current = null;
1111
1137
  saveTogglePosition(pos);
1112
1138
  }, [pos]);
1113
- return (_jsxs("div", { "data-slowcook-overlay-ui": "1", title: isApproved ? "Mockup approved — comments still allowed; plate refuses to amend" : undefined, style: {
1139
+ return (_jsxs("div", { ref: pillRef, "data-slowcook-overlay-ui": "1", title: isApproved ? "Mockup approved — comments still allowed; plate refuses to amend" : undefined, style: {
1114
1140
  position: "absolute",
1115
1141
  top: pos.top,
1116
1142
  left: pos.left,
@@ -1141,7 +1167,7 @@ function ModeToggle(props) {
1141
1167
  fontSize: 13,
1142
1168
  color: T.fg,
1143
1169
  userSelect: "none",
1144
- }, children: [_jsx("div", { role: "button", "aria-label": "Drag overlay toggle", onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerUp, title: "Drag to move", style: {
1170
+ }, children: [_jsx(CometSheen, { pillRef: pillRef, radius: 16 }), _jsx("div", { role: "button", "aria-label": "Drag overlay toggle", onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerUp, title: "Drag to move", style: {
1145
1171
  width: 11,
1146
1172
  alignSelf: "stretch",
1147
1173
  minHeight: 22,