proto-plugin 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.
Files changed (209) hide show
  1. package/AGENTS.md +350 -0
  2. package/README.md +279 -0
  3. package/components.json +18 -0
  4. package/package.json +73 -0
  5. package/scripts/download-mobbin-reference-images.mjs +112 -0
  6. package/scripts/lib/host-config.example.sh +48 -0
  7. package/scripts/lib/host-config.sh +25 -0
  8. package/scripts/lib/resolve-host-root.mjs +18 -0
  9. package/scripts/lib/source-path.sh +49 -0
  10. package/scripts/link-source-db.sh +128 -0
  11. package/scripts/link-source.sh +40 -0
  12. package/scripts/publish-package.sh +147 -0
  13. package/scripts/share-prototype.sh +279 -0
  14. package/scripts/sync-from-source.sh +74 -0
  15. package/scripts/verify-prototype-component-ids.mjs +151 -0
  16. package/scripts/verify-prototype-preview-states.mjs +135 -0
  17. package/src/app.ts +4 -0
  18. package/src/components/platform-ui/code-block.tsx +21 -0
  19. package/src/components/platform-ui/controls-panel-options.tsx +71 -0
  20. package/src/components/platform-ui/controls-panel-select.tsx +438 -0
  21. package/src/components/platform-ui/empty-state.tsx +15 -0
  22. package/src/components/platform-ui/icon-button.tsx +18 -0
  23. package/src/components/platform-ui/panel-select.tsx +123 -0
  24. package/src/components/platform-ui/panel.tsx +97 -0
  25. package/src/components/platform-ui/review-dropdown-menu.tsx +35 -0
  26. package/src/components/platform-ui/sidebar.tsx +293 -0
  27. package/src/components/platform-ui/toolbar-icon-button.tsx +34 -0
  28. package/src/components/platform-ui/toolbar.tsx +37 -0
  29. package/src/components/prototype-gallery-client.tsx +57 -0
  30. package/src/components/prototype-provider.tsx +20 -0
  31. package/src/components/prototypes/mini-pill-label.tsx +37 -0
  32. package/src/components/prototypes/prototype-change-log-panel.tsx +207 -0
  33. package/src/components/prototypes/prototype-comment-provider.tsx +61 -0
  34. package/src/components/prototypes/prototype-comment-toolbar.tsx +65 -0
  35. package/src/components/prototypes/prototype-control.tsx +31 -0
  36. package/src/components/prototypes/prototype-controls.tsx +553 -0
  37. package/src/components/prototypes/prototype-create-exploration-modal.tsx +117 -0
  38. package/src/components/prototypes/prototype-create-state-modal.tsx +117 -0
  39. package/src/components/prototypes/prototype-default-state-map-page.tsx +66 -0
  40. package/src/components/prototypes/prototype-design-brief-modal.tsx +128 -0
  41. package/src/components/prototypes/prototype-design-brief-panel.tsx +525 -0
  42. package/src/components/prototypes/prototype-design-context-panel.tsx +65 -0
  43. package/src/components/prototypes/prototype-floating-pill.module.scss +1341 -0
  44. package/src/components/prototypes/prototype-mobbin-gallery.tsx +330 -0
  45. package/src/components/prototypes/prototype-reference-docs.tsx +222 -0
  46. package/src/components/prototypes/prototype-review-chrome.module.scss +630 -0
  47. package/src/components/prototypes/prototype-review-chrome.tsx +1241 -0
  48. package/src/components/prototypes/prototype-review-dropdown-menu-item.tsx +1 -0
  49. package/src/components/prototypes/prototype-review-dropdown-menu-separator.tsx +1 -0
  50. package/src/components/prototypes/prototype-review-panel-menu-item.tsx +1 -0
  51. package/src/components/prototypes/prototype-review-panel-menu-separator.tsx +1 -0
  52. package/src/components/prototypes/prototype-review-panel-select.tsx +4 -0
  53. package/src/components/prototypes/prototype-review-sidebar.tsx +167 -0
  54. package/src/components/prototypes/prototype-share-link-restore.tsx +75 -0
  55. package/src/components/prototypes/prototype-share-mode.tsx +206 -0
  56. package/src/components/prototypes/prototype-spec-panel-content.tsx +538 -0
  57. package/src/components/prototypes/prototype-state-canvas-overlay.module.scss +336 -0
  58. package/src/components/prototypes/prototype-state-canvas-overlay.tsx +1023 -0
  59. package/src/components/prototypes/prototype-state-canvas.tsx +38 -0
  60. package/src/components/prototypes/prototype-state-screenshot-preview.tsx +47 -0
  61. package/src/components/prototypes/prototype-target.tsx +120 -0
  62. package/src/components/prototypes/prototype-tweak-highlight.tsx +132 -0
  63. package/src/components/prototypes/prototype-tweaks.tsx +48 -0
  64. package/src/components/prototypes/prototype-variant-explorer.tsx +347 -0
  65. package/src/components/prototypes/prototype-variant-rationale-panel.tsx +49 -0
  66. package/src/components/prototypes/prototype-variant-tabs.tsx +207 -0
  67. package/src/components/prototypes/prototype-vercel-preview-modal.tsx +120 -0
  68. package/src/components/prototypes/state-map-annotation-tooltip.module.scss +89 -0
  69. package/src/components/prototypes/state-map-annotation-tooltip.tsx +137 -0
  70. package/src/components/prototypes/state-map-wireframe-highlight.module.scss +25 -0
  71. package/src/components/prototypes/state-map-wireframe-highlight.tsx +82 -0
  72. package/src/components/shell/prototype-gallery-shell.tsx +79 -0
  73. package/src/components/shell/prototype-screenshot-capture.tsx +45 -0
  74. package/src/components/shell/prototype-shell.module.scss +194 -0
  75. package/src/components/shell/prototype-shell.tsx +160 -0
  76. package/src/components/shell/prototype-state-screenshot-capture.tsx +68 -0
  77. package/src/components/ui/button.tsx +58 -0
  78. package/src/components/ui/dialog.module.scss +81 -0
  79. package/src/components/ui/dialog.tsx +127 -0
  80. package/src/components/ui/dropdown-menu.tsx +200 -0
  81. package/src/components/ui/input.tsx +22 -0
  82. package/src/components/ui/label.tsx +26 -0
  83. package/src/components/ui/option-select.tsx +81 -0
  84. package/src/components/ui/scroll-area.tsx +48 -0
  85. package/src/components/ui/separator.tsx +31 -0
  86. package/src/components/ui/slider.tsx +28 -0
  87. package/src/components/ui/switch.tsx +29 -0
  88. package/src/components/ui/tabs.tsx +55 -0
  89. package/src/components/ui/toggle-group.tsx +80 -0
  90. package/src/components/ui/tooltip.tsx +32 -0
  91. package/src/config/create-prototype-gallery-page.tsx +65 -0
  92. package/src/config/create-prototype-host-app.tsx +121 -0
  93. package/src/config/create-prototype-page.tsx +41 -0
  94. package/src/config/create-prototype-site-layout.tsx +28 -0
  95. package/src/config/define-prototype-config.ts +7 -0
  96. package/src/config/prototype-icon.tsx +25 -0
  97. package/src/config/prototype-site-layout-client.tsx +35 -0
  98. package/src/config/with-prototype.ts +20 -0
  99. package/src/index.ts +303 -0
  100. package/src/lib/pr-split/build-pr-agent-prompt.ts +68 -0
  101. package/src/lib/pr-split/build-pr-split-prototype-url.ts +12 -0
  102. package/src/lib/pr-split/pr-split-highlight.ts +6 -0
  103. package/src/lib/pr-split/pr-split-types.ts +58 -0
  104. package/src/lib/pr-split/resolve-source-preview-url.ts +45 -0
  105. package/src/lib/pr-split/use-pr-vercel-previews.ts +69 -0
  106. package/src/lib/prototype-comments/core/annotation-channel.ts +41 -0
  107. package/src/lib/prototype-comments/core/annotation-status.ts +60 -0
  108. package/src/lib/prototype-comments/core/annotation-target.ts +567 -0
  109. package/src/lib/prototype-comments/core/capture-theme.ts +41 -0
  110. package/src/lib/prototype-comments/core/capture.ts +11 -0
  111. package/src/lib/prototype-comments/core/comment-capture-blocked.ts +47 -0
  112. package/src/lib/prototype-comments/core/comment-threads.ts +52 -0
  113. package/src/lib/prototype-comments/core/element-identification.ts +615 -0
  114. package/src/lib/prototype-comments/core/export.ts +35 -0
  115. package/src/lib/prototype-comments/core/freeze-animations.ts +266 -0
  116. package/src/lib/prototype-comments/core/identify-element.ts +76 -0
  117. package/src/lib/prototype-comments/core/normalize-viewport.ts +35 -0
  118. package/src/lib/prototype-comments/core/react-detection.ts +704 -0
  119. package/src/lib/prototype-comments/core/restore.ts +7 -0
  120. package/src/lib/prototype-comments/core/screenshot.ts +428 -0
  121. package/src/lib/prototype-comments/core/source-location.ts +906 -0
  122. package/src/lib/prototype-comments/core/storage.ts +80 -0
  123. package/src/lib/prototype-comments/core/types.ts +79 -0
  124. package/src/lib/prototype-comments/core/validation.ts +17 -0
  125. package/src/lib/prototype-comments/hooks/useLayoutShift.ts +61 -0
  126. package/src/lib/prototype-comments/index.ts +58 -0
  127. package/src/lib/prototype-comments/react/CommentCaptureToolbar.tsx +1398 -0
  128. package/src/lib/prototype-comments/react/CommentProvider.tsx +298 -0
  129. package/src/lib/prototype-comments/scss.d.ts +10 -0
  130. package/src/lib/prototype-comments/ui/CommentAnnotationOverlay.tsx +253 -0
  131. package/src/lib/prototype-comments/ui/CommentDetailPage.tsx +56 -0
  132. package/src/lib/prototype-comments/ui/CommentHeaderCount.tsx +28 -0
  133. package/src/lib/prototype-comments/ui/CommentThread.tsx +331 -0
  134. package/src/lib/prototype-comments/ui/CommentsGrid.tsx +780 -0
  135. package/src/lib/prototype-comments/ui/CommentsListPage.tsx +25 -0
  136. package/src/lib/prototype-comments/ui/CommentsSidebar.tsx +77 -0
  137. package/src/lib/prototype-comments/ui/annotation-marker/index.tsx +200 -0
  138. package/src/lib/prototype-comments/ui/annotation-marker/styles.module.scss +194 -0
  139. package/src/lib/prototype-comments/ui/annotation-popup/index.tsx +335 -0
  140. package/src/lib/prototype-comments/ui/annotation-popup/styles.module.scss +469 -0
  141. package/src/lib/prototype-comments/ui/capture-styles.module.scss +2225 -0
  142. package/src/lib/prototype-comments/ui/comment-highlight.ts +48 -0
  143. package/src/lib/prototype-comments/ui/comment-thread.module.scss +203 -0
  144. package/src/lib/prototype-comments/ui/comments-grid-card.module.scss +253 -0
  145. package/src/lib/prototype-comments/ui/comments-sidebar.module.scss +123 -0
  146. package/src/lib/prototype-comments/ui/icon-transitions.module.scss +51 -0
  147. package/src/lib/prototype-comments/ui/icons.tsx +1086 -0
  148. package/src/lib/prototype-comments/ui/is-comment-detail-path.ts +7 -0
  149. package/src/lib/prototypes/capture-prototype-viewport.ts +32 -0
  150. package/src/lib/prototypes/changelog-meta-context.tsx +162 -0
  151. package/src/lib/prototypes/changelog-meta-storage.ts +62 -0
  152. package/src/lib/prototypes/changelog-meta.ts +95 -0
  153. package/src/lib/prototypes/create-prototype-registry.ts +74 -0
  154. package/src/lib/prototypes/create-state-screenshot-thumbnail.ts +46 -0
  155. package/src/lib/prototypes/design-exploration-default-storage.ts +68 -0
  156. package/src/lib/prototypes/design-exploration-default.ts +51 -0
  157. package/src/lib/prototypes/design-exploration-types.ts +203 -0
  158. package/src/lib/prototypes/prototype-comment-registry.tsx +145 -0
  159. package/src/lib/prototypes/prototype-comment-review-bridge.tsx +40 -0
  160. package/src/lib/prototypes/prototype-comment-review-state.ts +57 -0
  161. package/src/lib/prototypes/prototype-component-registry.ts +40 -0
  162. package/src/lib/prototypes/prototype-config-types.ts +34 -0
  163. package/src/lib/prototypes/prototype-preview-state-registry.ts +443 -0
  164. package/src/lib/prototypes/prototype-preview-state-types.ts +89 -0
  165. package/src/lib/prototypes/prototype-review-context.tsx +905 -0
  166. package/src/lib/prototypes/prototype-review-url.ts +134 -0
  167. package/src/lib/prototypes/prototype-share-link.ts +175 -0
  168. package/src/lib/prototypes/prototype-state-canvas-constants.ts +118 -0
  169. package/src/lib/prototypes/prototype-state-canvas-types.ts +159 -0
  170. package/src/lib/prototypes/prototype-state-screenshot.ts +39 -0
  171. package/src/lib/prototypes/prototype-tweak-registry.ts +96 -0
  172. package/src/lib/prototypes/prototype-tweak-types.ts +31 -0
  173. package/src/lib/prototypes/reference-docs.ts +137 -0
  174. package/src/lib/prototypes/screenshot-manifest.ts +33 -0
  175. package/src/lib/prototypes/screenshot-src.ts +7 -0
  176. package/src/lib/prototypes/share-command.ts +8 -0
  177. package/src/lib/prototypes/state-map-annotation.ts +70 -0
  178. package/src/lib/prototypes/use-design-exploration-default.ts +114 -0
  179. package/src/lib/prototypes/use-persisted-local-state.ts +140 -0
  180. package/src/lib/prototypes/use-prototype-comments.ts +63 -0
  181. package/src/lib/prototypes/use-prototype-mobile-viewport-frame.ts +46 -0
  182. package/src/lib/prototypes/use-prototype-state-screenshot-src.ts +71 -0
  183. package/src/lib/prototypes/use-prototype-tool-theme.tsx +115 -0
  184. package/src/lib/prototypes/use-prototype-viewport-frame.ts +34 -0
  185. package/src/lib/prototypes/use-register-prototype-reference-docs.ts +16 -0
  186. package/src/lib/prototypes/use-snap-corner-position.ts +417 -0
  187. package/src/lib/prototypes/use-toolbar-hover-panel.ts +98 -0
  188. package/src/lib/prototypes/variant-set-lucide-icon.tsx +55 -0
  189. package/src/lib/tool-portal.ts +33 -0
  190. package/src/lib/use-copy-to-clipboard.ts +81 -0
  191. package/src/lib/utils.ts +6 -0
  192. package/src/lib/vercel-preview/parse-vercel-github-comment.ts +81 -0
  193. package/src/server/create-host-api-route.ts +100 -0
  194. package/src/server/create-prototype-api-routes.ts +428 -0
  195. package/src/server/gallery/create-gallery-api.ts +56 -0
  196. package/src/server/gallery/folders-route.ts +156 -0
  197. package/src/server/gallery/gallery-env.ts +39 -0
  198. package/src/server/gallery/gallery-route.ts +150 -0
  199. package/src/server/gallery/gallery-types.ts +15 -0
  200. package/src/server/gallery/image-route.ts +59 -0
  201. package/src/server/gallery/item-route.ts +92 -0
  202. package/src/server/pr-vercel-preview-route.ts +162 -0
  203. package/src/server/redis/client.ts +55 -0
  204. package/src/server/redis/prototype-changelog-meta.ts +31 -0
  205. package/src/server/redis/prototype-comments.ts +92 -0
  206. package/src/server/redis/prototype-design-exploration-default.ts +32 -0
  207. package/src/server.ts +51 -0
  208. package/src/styles/globals.css +624 -0
  209. package/tsconfig.json +19 -0
@@ -0,0 +1,266 @@
1
+ // =============================================================================
2
+ // Freeze Animations
3
+ // =============================================================================
4
+ //
5
+ // Monkey-patches setTimeout, setInterval, and requestAnimationFrame so that
6
+ // callbacks are silently skipped while frozen. Also injects CSS to pause
7
+ // CSS animations/transitions, pauses WAAPI animations, and pauses videos.
8
+ //
9
+ // Toolbar/popup code must import `originalSetTimeout` etc. to bypass the patch.
10
+ //
11
+ // Patches are installed as a side effect of importing this module.
12
+ // =============================================================================
13
+
14
+ // Exclude selectors — prototype comment UI elements should never be frozen
15
+ const EXCLUDE_ATTRS = [
16
+ "data-feedback-toolbar",
17
+ "data-annotation-popup",
18
+ "data-annotation-marker",
19
+ ];
20
+ const NOT_SELECTORS = EXCLUDE_ATTRS
21
+ .flatMap((a) => [`:not([${a}])`, `:not([${a}] *)`])
22
+ .join("");
23
+
24
+ const STYLE_ID = "feedback-freeze-styles";
25
+ const STATE_KEY = "__prototype_comment_freeze";
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Shared mutable state on window (survives HMR module re-execution)
29
+ // ---------------------------------------------------------------------------
30
+ interface FreezeState {
31
+ frozen: boolean;
32
+ installed: boolean;
33
+ origSetTimeout: typeof setTimeout;
34
+ origSetInterval: typeof setInterval;
35
+ origRAF: typeof requestAnimationFrame;
36
+ // Queues live on window so they survive HMR module re-execution
37
+ pausedAnimations: Animation[];
38
+ frozenTimeoutQueue: Array<() => void>;
39
+ frozenRAFQueue: FrameRequestCallback[];
40
+ }
41
+
42
+ function getState(): FreezeState {
43
+ if (typeof window === "undefined") {
44
+ // SSR stub
45
+ return {
46
+ frozen: false,
47
+ installed: true, // prevent patching on server
48
+ origSetTimeout: setTimeout,
49
+ origSetInterval: setInterval,
50
+ origRAF: (cb: FrameRequestCallback) => 0 as any,
51
+ pausedAnimations: [],
52
+ frozenTimeoutQueue: [],
53
+ frozenRAFQueue: [],
54
+ };
55
+ }
56
+ const w = window as any;
57
+ if (!w[STATE_KEY]) {
58
+ w[STATE_KEY] = {
59
+ frozen: false,
60
+ installed: false,
61
+ origSetTimeout: null,
62
+ origSetInterval: null,
63
+ origRAF: null,
64
+ pausedAnimations: [],
65
+ frozenTimeoutQueue: [],
66
+ frozenRAFQueue: [],
67
+ };
68
+ }
69
+ return w[STATE_KEY];
70
+ }
71
+
72
+ const _s = getState();
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // Install patches (once — survives HMR because `installed` lives on window)
76
+ // ---------------------------------------------------------------------------
77
+ if (typeof window !== "undefined" && !_s.installed) {
78
+ // Save the real functions
79
+ _s.origSetTimeout = window.setTimeout.bind(window);
80
+ _s.origSetInterval = window.setInterval.bind(window);
81
+ _s.origRAF = window.requestAnimationFrame.bind(window);
82
+
83
+ // Patch setTimeout — queue callback when frozen (replayed on unfreeze)
84
+ (window as any).setTimeout = (
85
+ handler: TimerHandler,
86
+ timeout?: number,
87
+ ...args: any[]
88
+ ): ReturnType<typeof setTimeout> => {
89
+ if (typeof handler === "string") {
90
+ return _s.origSetTimeout(handler, timeout) as unknown as ReturnType<typeof setTimeout>;
91
+ }
92
+ return _s.origSetTimeout(
93
+ (...a: any[]) => {
94
+ if (_s.frozen) {
95
+ _s.frozenTimeoutQueue.push(() => (handler as Function)(...a));
96
+ } else {
97
+ (handler as Function)(...a);
98
+ }
99
+ },
100
+ timeout,
101
+ ...args,
102
+ );
103
+ };
104
+
105
+ // Patch setInterval — skip callback when frozen
106
+ (window as any).setInterval = (
107
+ handler: TimerHandler,
108
+ timeout?: number,
109
+ ...args: any[]
110
+ ): ReturnType<typeof setInterval> => {
111
+ if (typeof handler === "string") {
112
+ return _s.origSetInterval(handler, timeout) as unknown as ReturnType<typeof setInterval>;
113
+ }
114
+ return _s.origSetInterval(
115
+ (...a: any[]) => {
116
+ if (!_s.frozen) (handler as Function)(...a);
117
+ },
118
+ timeout,
119
+ ...args,
120
+ );
121
+ };
122
+
123
+ // Patch requestAnimationFrame — queue callback when frozen (no CPU spin)
124
+ // The wrapper fires once on the next frame; if still frozen the callback
125
+ // is stored in _s.frozenRAFQueue and replayed on unfreeze.
126
+ (window as any).requestAnimationFrame = (
127
+ callback: FrameRequestCallback,
128
+ ): number => {
129
+ return _s.origRAF((timestamp: number) => {
130
+ if (_s.frozen) {
131
+ _s.frozenRAFQueue.push(callback);
132
+ } else {
133
+ callback(timestamp);
134
+ }
135
+ });
136
+ };
137
+
138
+ _s.installed = true;
139
+ }
140
+
141
+ // ---------------------------------------------------------------------------
142
+ // Exports — original (unpatched) timing functions for toolbar/popup use
143
+ // ---------------------------------------------------------------------------
144
+ export const originalSetTimeout = _s.origSetTimeout;
145
+ export const originalSetInterval = _s.origSetInterval;
146
+ export const originalRequestAnimationFrame = _s.origRAF;
147
+
148
+ // ---------------------------------------------------------------------------
149
+ // Freeze / Unfreeze
150
+ // ---------------------------------------------------------------------------
151
+
152
+ function isPrototypeCommentChromeElement(el: Element | null): boolean {
153
+ if (!el) return false;
154
+ return EXCLUDE_ATTRS.some((attr) => !!el.closest?.(`[${attr}]`));
155
+ }
156
+
157
+ export function freeze(): void {
158
+ if (typeof document === "undefined") return;
159
+ if (_s.frozen) return;
160
+ _s.frozen = true;
161
+ _s.frozenTimeoutQueue = [];
162
+ _s.frozenRAFQueue = [];
163
+
164
+ // CSS injection — pause CSS animations and kill transitions
165
+ let style = document.getElementById(STYLE_ID);
166
+ if (!style) {
167
+ style = document.createElement("style");
168
+ style.id = STYLE_ID;
169
+ }
170
+ style.textContent = `
171
+ *${NOT_SELECTORS},
172
+ *${NOT_SELECTORS}::before,
173
+ *${NOT_SELECTORS}::after {
174
+ animation-play-state: paused !important;
175
+ transition: none !important;
176
+ }
177
+ `;
178
+ document.head.appendChild(style);
179
+
180
+ // WAAPI — pause only RUNNING non-prototype-comment animations and store references
181
+ // (pausing finished animations would restart them on play(), breaking entrance anims)
182
+ _s.pausedAnimations = [];
183
+ try {
184
+ document.getAnimations().forEach((anim) => {
185
+ if (anim.playState !== "running") return;
186
+ const target = (anim.effect as KeyframeEffect)?.target as Element | null;
187
+ if (!isPrototypeCommentChromeElement(target)) {
188
+ anim.pause();
189
+ _s.pausedAnimations.push(anim);
190
+ }
191
+ });
192
+ } catch {
193
+ // getAnimations may not be available in all environments
194
+ }
195
+
196
+ // Pause videos
197
+ document.querySelectorAll("video").forEach((video) => {
198
+ if (!video.paused) {
199
+ video.dataset.wasPaused = "false";
200
+ video.pause();
201
+ }
202
+ });
203
+ }
204
+
205
+ export function unfreeze(): void {
206
+ if (typeof document === "undefined") return;
207
+ if (!_s.frozen) return;
208
+ _s.frozen = false;
209
+
210
+ // Replay queued setTimeout callbacks asynchronously (resolves stuck delay()
211
+ // Promises, restarts animation loops interrupted by visibilitychange, etc.)
212
+ // Using origSetTimeout(cb, 0) avoids blocking the main thread in one go.
213
+ // Re-check _s.frozen before executing — if freeze() was called again between
214
+ // scheduling and execution, re-queue the callback instead of running it.
215
+ const timeoutQueue = _s.frozenTimeoutQueue;
216
+ _s.frozenTimeoutQueue = [];
217
+ for (const cb of timeoutQueue) {
218
+ _s.origSetTimeout(() => {
219
+ if (_s.frozen) {
220
+ _s.frozenTimeoutQueue.push(cb);
221
+ return;
222
+ }
223
+ try {
224
+ cb();
225
+ } catch (e) {
226
+ console.warn("[prototype-comments] Error replaying queued timeout:", e);
227
+ }
228
+ }, 0);
229
+ }
230
+
231
+ // Schedule queued rAF callbacks for the next frame.
232
+ // Re-check _s.frozen — if re-frozen before the frame fires, re-queue.
233
+ const rafQueue = _s.frozenRAFQueue;
234
+ _s.frozenRAFQueue = [];
235
+ for (const cb of rafQueue) {
236
+ _s.origRAF((ts: number) => {
237
+ if (_s.frozen) {
238
+ _s.frozenRAFQueue.push(cb);
239
+ return;
240
+ }
241
+ cb(ts);
242
+ });
243
+ }
244
+
245
+ // WAAPI — resume the exact animations we paused BEFORE removing CSS
246
+ // (removing CSS first can cause the browser to replace animation objects)
247
+ for (const anim of _s.pausedAnimations) {
248
+ try {
249
+ anim.play();
250
+ } catch (e) {
251
+ console.warn("[prototype-comments] Error resuming animation:", e);
252
+ }
253
+ }
254
+ _s.pausedAnimations = [];
255
+
256
+ // Now remove CSS injection
257
+ document.getElementById(STYLE_ID)?.remove();
258
+
259
+ // Resume videos
260
+ document.querySelectorAll("video").forEach((video) => {
261
+ if (video.dataset.wasPaused === "false") {
262
+ video.play().catch(() => {});
263
+ delete video.dataset.wasPaused;
264
+ }
265
+ });
266
+ }
@@ -0,0 +1,76 @@
1
+ import {
2
+ getAccessibilityInfo,
3
+ getDetailedComputedStyles,
4
+ getElementClasses,
5
+ getElementPath,
6
+ getForensicComputedStyles,
7
+ getFullElementPath,
8
+ getNearbyElements,
9
+ getNearbyText,
10
+ identifyElement,
11
+ } from "./element-identification";
12
+ import { getReactComponentName } from "./react-detection";
13
+ import {
14
+ formatSourceLocation,
15
+ findNearestComponentSource,
16
+ getSourceLocation,
17
+ } from "./source-location";
18
+
19
+ export type ReactComponentMode = "smart" | "filtered" | "all" | "off";
20
+
21
+ export function identifyElementWithReact(
22
+ element: HTMLElement,
23
+ reactMode: ReactComponentMode = "filtered",
24
+ ): {
25
+ name: string;
26
+ elementName: string;
27
+ path: string;
28
+ reactComponents: string | null;
29
+ } {
30
+ const { name: elementName, path } = identifyElement(element);
31
+
32
+ if (reactMode === "off") {
33
+ return { name: elementName, elementName, path, reactComponents: null };
34
+ }
35
+
36
+ const reactInfo = getReactComponentName(element, { mode: reactMode });
37
+
38
+ return {
39
+ name: reactInfo.path ? `${reactInfo.path} ${elementName}` : elementName,
40
+ elementName,
41
+ path,
42
+ reactComponents: reactInfo.path,
43
+ };
44
+ }
45
+
46
+ export function isElementFixed(element: HTMLElement): boolean {
47
+ let current: HTMLElement | null = element;
48
+ while (current && current !== document.body) {
49
+ const style = window.getComputedStyle(current);
50
+ const position = style.position;
51
+ if (position === "fixed" || position === "sticky") {
52
+ return true;
53
+ }
54
+ current = current.parentElement;
55
+ }
56
+ return false;
57
+ }
58
+
59
+ export function detectSourceFile(element: Element): string | undefined {
60
+ const result = getSourceLocation(element as HTMLElement);
61
+ const loc = result.found ? result : findNearestComponentSource(element as HTMLElement);
62
+ if (loc.found && loc.source) {
63
+ return formatSourceLocation(loc.source, "path");
64
+ }
65
+ return undefined;
66
+ }
67
+
68
+ export {
69
+ getAccessibilityInfo,
70
+ getDetailedComputedStyles,
71
+ getElementClasses,
72
+ getForensicComputedStyles,
73
+ getFullElementPath,
74
+ getNearbyElements,
75
+ getNearbyText,
76
+ };
@@ -0,0 +1,35 @@
1
+ import type { AnnotationBoundingBox, CaptureViewport, CommentAnnotationFields } from "./types";
2
+
3
+ type ViewportNormalizeInput = Pick<
4
+ CommentAnnotationFields,
5
+ "boundingBox" | "isFixed" | "viewportBoundingBox" | "captureViewport"
6
+ >;
7
+
8
+ export function normalizeAnnotationViewport(annotation: ViewportNormalizeInput): {
9
+ captureViewport: CaptureViewport | undefined;
10
+ viewportBoundingBox: AnnotationBoundingBox | undefined;
11
+ } {
12
+ const captureViewport =
13
+ annotation.captureViewport ??
14
+ (typeof window !== "undefined"
15
+ ? {
16
+ width: window.innerWidth,
17
+ height: window.innerHeight,
18
+ scrollY: window.scrollY,
19
+ }
20
+ : undefined);
21
+
22
+ const viewportBoundingBox =
23
+ annotation.boundingBox && captureViewport
24
+ ? {
25
+ x: annotation.boundingBox.x,
26
+ y: annotation.isFixed
27
+ ? annotation.boundingBox.y
28
+ : annotation.boundingBox.y - captureViewport.scrollY,
29
+ width: annotation.boundingBox.width,
30
+ height: annotation.boundingBox.height,
31
+ }
32
+ : annotation.viewportBoundingBox;
33
+
34
+ return { captureViewport, viewportBoundingBox };
35
+ }