claw-design 1.0.1

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/cli/commands/start.d.ts +7 -0
  4. package/dist/cli/commands/start.d.ts.map +1 -0
  5. package/dist/cli/commands/start.js +176 -0
  6. package/dist/cli/commands/start.js.map +1 -0
  7. package/dist/cli/index.d.ts +3 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +20 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/utils/claude.d.ts +21 -0
  12. package/dist/cli/utils/claude.d.ts.map +1 -0
  13. package/dist/cli/utils/claude.js +42 -0
  14. package/dist/cli/utils/claude.js.map +1 -0
  15. package/dist/cli/utils/dev-server.d.ts +14 -0
  16. package/dist/cli/utils/dev-server.d.ts.map +1 -0
  17. package/dist/cli/utils/dev-server.js +57 -0
  18. package/dist/cli/utils/dev-server.js.map +1 -0
  19. package/dist/cli/utils/electron.d.ts +7 -0
  20. package/dist/cli/utils/electron.d.ts.map +1 -0
  21. package/dist/cli/utils/electron.js +36 -0
  22. package/dist/cli/utils/electron.js.map +1 -0
  23. package/dist/cli/utils/output.d.ts +6 -0
  24. package/dist/cli/utils/output.d.ts.map +1 -0
  25. package/dist/cli/utils/output.js +21 -0
  26. package/dist/cli/utils/output.js.map +1 -0
  27. package/dist/cli/utils/port-detect.d.ts +30 -0
  28. package/dist/cli/utils/port-detect.d.ts.map +1 -0
  29. package/dist/cli/utils/port-detect.js +95 -0
  30. package/dist/cli/utils/port-detect.js.map +1 -0
  31. package/dist/cli/utils/preflight.d.ts +20 -0
  32. package/dist/cli/utils/preflight.d.ts.map +1 -0
  33. package/dist/cli/utils/preflight.js +33 -0
  34. package/dist/cli/utils/preflight.js.map +1 -0
  35. package/dist/cli/utils/process.d.ts +23 -0
  36. package/dist/cli/utils/process.d.ts.map +1 -0
  37. package/dist/cli/utils/process.js +57 -0
  38. package/dist/cli/utils/process.js.map +1 -0
  39. package/out/main/index.js +1123 -0
  40. package/out/preload/overlay.cjs +56 -0
  41. package/out/preload/sidebar.cjs +29 -0
  42. package/out/renderer/assets/overlay-Bsx1u_qg.css +449 -0
  43. package/out/renderer/assets/overlay-DZl3I3jq.js +689 -0
  44. package/out/renderer/assets/sidebar-Bt34gvPU.js +563 -0
  45. package/out/renderer/assets/sidebar-BxEPS84k.css +515 -0
  46. package/out/renderer/assets/toast-CLlgwMU_.js +110 -0
  47. package/out/renderer/overlay.html +131 -0
  48. package/out/renderer/sidebar.html +64 -0
  49. package/package.json +67 -0
  50. package/resources/icon.icns +0 -0
  51. package/resources/icon.png +0 -0
  52. package/scripts/postinstall.cjs +56 -0
@@ -0,0 +1,689 @@
1
+ const scriptRel = /* @__PURE__ */ (function detectScriptRel() {
2
+ const relList = typeof document !== "undefined" && document.createElement("link").relList;
3
+ return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload";
4
+ })();
5
+ const assetsURL = function(dep, importerUrl) {
6
+ return new URL(dep, importerUrl).href;
7
+ };
8
+ const seen = {};
9
+ const __vitePreload = function preload(baseModule, deps, importerUrl) {
10
+ let promise = Promise.resolve();
11
+ if (deps && deps.length > 0) {
12
+ let allSettled = function(promises$2) {
13
+ return Promise.all(promises$2.map((p) => Promise.resolve(p).then((value$1) => ({
14
+ status: "fulfilled",
15
+ value: value$1
16
+ }), (reason) => ({
17
+ status: "rejected",
18
+ reason
19
+ }))));
20
+ };
21
+ const links = document.getElementsByTagName("link");
22
+ const cspNonceMeta = document.querySelector("meta[property=csp-nonce]");
23
+ const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
24
+ promise = allSettled(deps.map((dep) => {
25
+ dep = assetsURL(dep, importerUrl);
26
+ if (dep in seen) return;
27
+ seen[dep] = true;
28
+ const isCss = dep.endsWith(".css");
29
+ const cssSelector = isCss ? '[rel="stylesheet"]' : "";
30
+ if (!!importerUrl) for (let i$1 = links.length - 1; i$1 >= 0; i$1--) {
31
+ const link$1 = links[i$1];
32
+ if (link$1.href === dep && (!isCss || link$1.rel === "stylesheet")) return;
33
+ }
34
+ else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) return;
35
+ const link = document.createElement("link");
36
+ link.rel = isCss ? "stylesheet" : scriptRel;
37
+ if (!isCss) link.as = "script";
38
+ link.crossOrigin = "";
39
+ link.href = dep;
40
+ if (cspNonce) link.setAttribute("nonce", cspNonce);
41
+ document.head.appendChild(link);
42
+ if (isCss) return new Promise((res, rej) => {
43
+ link.addEventListener("load", res);
44
+ link.addEventListener("error", () => rej(/* @__PURE__ */ new Error(`Unable to preload CSS for ${dep}`)));
45
+ });
46
+ }));
47
+ }
48
+ function handlePreloadError(err$2) {
49
+ const e$1 = new Event("vite:preloadError", { cancelable: true });
50
+ e$1.payload = err$2;
51
+ window.dispatchEvent(e$1);
52
+ if (!e$1.defaultPrevented) throw err$2;
53
+ }
54
+ return promise.then((res) => {
55
+ for (const item of res || []) {
56
+ if (item.status !== "rejected") continue;
57
+ handlePreloadError(item.reason);
58
+ }
59
+ return baseModule().catch(handlePreloadError);
60
+ });
61
+ };
62
+ const INITIAL_STATE = {
63
+ mode: "inactive",
64
+ startX: 0,
65
+ startY: 0,
66
+ currentX: 0,
67
+ currentY: 0,
68
+ hoveredRect: null,
69
+ selectionBounds: null
70
+ };
71
+ const MIN_SELECTION_SIZE = 16;
72
+ function transition(state, event) {
73
+ switch (event.type) {
74
+ case "ACTIVATE_RECT": {
75
+ if (state.mode === "inactive" || state.mode === "rect-committed" || state.mode === "elem-committed" || state.mode === "elem-idle" || state.mode === "elem-hovering") {
76
+ return { ...INITIAL_STATE, mode: "rect-idle" };
77
+ }
78
+ return state;
79
+ }
80
+ case "ACTIVATE_ELEM": {
81
+ if (state.mode === "inactive" || state.mode === "rect-committed" || state.mode === "elem-committed" || state.mode === "rect-idle" || state.mode === "rect-drawing") {
82
+ return { ...INITIAL_STATE, mode: "elem-idle" };
83
+ }
84
+ return state;
85
+ }
86
+ case "MOUSE_DOWN": {
87
+ if (state.mode === "rect-idle") {
88
+ return {
89
+ ...state,
90
+ mode: "rect-drawing",
91
+ startX: event.x,
92
+ startY: event.y,
93
+ currentX: event.x,
94
+ currentY: event.y
95
+ };
96
+ }
97
+ return state;
98
+ }
99
+ case "MOUSE_MOVE": {
100
+ if (state.mode === "rect-drawing") {
101
+ return {
102
+ ...state,
103
+ currentX: event.x,
104
+ currentY: event.y
105
+ };
106
+ }
107
+ return state;
108
+ }
109
+ case "MOUSE_UP": {
110
+ if (state.mode === "rect-drawing") {
111
+ const x = Math.min(state.startX, event.x);
112
+ const y = Math.min(state.startY, event.y);
113
+ const width = Math.abs(event.x - state.startX);
114
+ const height = Math.abs(event.y - state.startY);
115
+ if (width >= MIN_SELECTION_SIZE && height >= MIN_SELECTION_SIZE) {
116
+ return {
117
+ ...state,
118
+ mode: "rect-committed",
119
+ currentX: event.x,
120
+ currentY: event.y,
121
+ selectionBounds: { x, y, width, height }
122
+ };
123
+ }
124
+ return {
125
+ ...state,
126
+ mode: "rect-idle",
127
+ startX: 0,
128
+ startY: 0,
129
+ currentX: 0,
130
+ currentY: 0,
131
+ selectionBounds: null
132
+ };
133
+ }
134
+ return state;
135
+ }
136
+ case "ELEMENT_HOVER": {
137
+ if (state.mode === "elem-idle" || state.mode === "elem-hovering") {
138
+ return {
139
+ ...state,
140
+ mode: "elem-hovering",
141
+ hoveredRect: event.rect
142
+ };
143
+ }
144
+ return state;
145
+ }
146
+ case "ELEMENT_CLICK": {
147
+ if (state.mode === "elem-hovering" && state.hoveredRect) {
148
+ return {
149
+ ...state,
150
+ mode: "elem-committed",
151
+ selectionBounds: state.hoveredRect
152
+ };
153
+ }
154
+ return state;
155
+ }
156
+ case "CANCEL": {
157
+ if (state.mode !== "inactive") {
158
+ return { ...INITIAL_STATE };
159
+ }
160
+ return state;
161
+ }
162
+ default:
163
+ return state;
164
+ }
165
+ }
166
+ function isInBrowser() {
167
+ return typeof document !== "undefined" && typeof window !== "undefined";
168
+ }
169
+ if (isInBrowser()) {
170
+ let dispatch = function(event) {
171
+ const prev = state;
172
+ state = transition(state, event);
173
+ if (state !== prev) {
174
+ render(state);
175
+ if (state.mode !== "inactive" && onModeChange) {
176
+ onModeChange();
177
+ }
178
+ }
179
+ }, render = function(s) {
180
+ const selectionRect = document.getElementById("claw-selection-rect");
181
+ const elementHighlight = document.getElementById("claw-element-highlight");
182
+ const selectBtn2 = document.getElementById("claw-select-btn");
183
+ const elemBtn2 = document.getElementById("claw-elem-btn");
184
+ if (s.mode === "rect-idle" || s.mode === "rect-drawing") {
185
+ document.body.style.cursor = "crosshair";
186
+ } else {
187
+ document.body.style.cursor = "default";
188
+ }
189
+ if (selectionRect) {
190
+ if (s.mode === "rect-drawing" || s.mode === "rect-committed") {
191
+ selectionRect.hidden = false;
192
+ if (s.mode === "rect-drawing") {
193
+ const x = Math.min(s.startX, s.currentX);
194
+ const y = Math.min(s.startY, s.currentY);
195
+ const w = Math.abs(s.currentX - s.startX);
196
+ const h = Math.abs(s.currentY - s.startY);
197
+ selectionRect.style.left = `${x}px`;
198
+ selectionRect.style.top = `${y}px`;
199
+ selectionRect.style.width = `${w}px`;
200
+ selectionRect.style.height = `${h}px`;
201
+ selectionRect.classList.add("claw-selection-rect--drawing");
202
+ selectionRect.classList.remove("claw-selection-rect--committed");
203
+ } else if (s.mode === "rect-committed" && s.selectionBounds) {
204
+ selectionRect.style.left = `${s.selectionBounds.x}px`;
205
+ selectionRect.style.top = `${s.selectionBounds.y}px`;
206
+ selectionRect.style.width = `${s.selectionBounds.width}px`;
207
+ selectionRect.style.height = `${s.selectionBounds.height}px`;
208
+ selectionRect.classList.remove("claw-selection-rect--drawing");
209
+ selectionRect.classList.add("claw-selection-rect--committed");
210
+ }
211
+ } else {
212
+ selectionRect.hidden = true;
213
+ selectionRect.classList.remove(
214
+ "claw-selection-rect--drawing",
215
+ "claw-selection-rect--committed"
216
+ );
217
+ }
218
+ }
219
+ if (elementHighlight) {
220
+ if (s.mode === "elem-hovering" && s.hoveredRect) {
221
+ elementHighlight.hidden = false;
222
+ elementHighlight.style.left = `${s.hoveredRect.x}px`;
223
+ elementHighlight.style.top = `${s.hoveredRect.y}px`;
224
+ elementHighlight.style.width = `${s.hoveredRect.width}px`;
225
+ elementHighlight.style.height = `${s.hoveredRect.height}px`;
226
+ elementHighlight.classList.add("claw-element-highlight--visible");
227
+ elementHighlight.classList.remove("claw-element-highlight--committed");
228
+ } else if (s.mode === "elem-committed" && s.selectionBounds) {
229
+ elementHighlight.hidden = false;
230
+ elementHighlight.style.left = `${s.selectionBounds.x}px`;
231
+ elementHighlight.style.top = `${s.selectionBounds.y}px`;
232
+ elementHighlight.style.width = `${s.selectionBounds.width}px`;
233
+ elementHighlight.style.height = `${s.selectionBounds.height}px`;
234
+ elementHighlight.classList.remove("claw-element-highlight--visible");
235
+ elementHighlight.classList.add("claw-element-highlight--committed");
236
+ } else {
237
+ elementHighlight.hidden = true;
238
+ elementHighlight.classList.remove(
239
+ "claw-element-highlight--visible",
240
+ "claw-element-highlight--committed"
241
+ );
242
+ }
243
+ }
244
+ if (selectBtn2) {
245
+ if (s.mode === "rect-idle" || s.mode === "rect-drawing" || s.mode === "rect-committed") {
246
+ selectBtn2.classList.add("claw-toolbar-btn--active");
247
+ } else {
248
+ selectBtn2.classList.remove("claw-toolbar-btn--active");
249
+ }
250
+ }
251
+ if (elemBtn2) {
252
+ if (s.mode === "elem-idle" || s.mode === "elem-hovering" || s.mode === "elem-committed") {
253
+ elemBtn2.classList.add("claw-toolbar-btn--active");
254
+ } else {
255
+ elemBtn2.classList.remove("claw-toolbar-btn--active");
256
+ }
257
+ }
258
+ if ((s.mode === "rect-committed" || s.mode === "elem-committed") && s.selectionBounds) {
259
+ document.dispatchEvent(
260
+ new CustomEvent("claw:selection-committed", {
261
+ detail: { bounds: s.selectionBounds }
262
+ })
263
+ );
264
+ }
265
+ }, captureToolbarLocalRect = function() {
266
+ return toolbar ? toolbar.getBoundingClientRect() : null;
267
+ }, activateOverlaySurface = function(localRect, viewBounds) {
268
+ if (toolbar && localRect && viewBounds) {
269
+ toolbar.style.position = "fixed";
270
+ toolbar.style.left = `${viewBounds.x + localRect.left}px`;
271
+ toolbar.style.top = `${viewBounds.y + localRect.top}px`;
272
+ toolbar.style.bottom = "auto";
273
+ toolbar.style.right = "auto";
274
+ }
275
+ document.body.classList.add("claw-overlay--active");
276
+ }, deactivateOverlaySurface = function() {
277
+ document.body.classList.remove("claw-overlay--active");
278
+ if (toolbar) {
279
+ toolbar.style.position = "";
280
+ toolbar.style.left = "";
281
+ toolbar.style.top = "";
282
+ toolbar.style.bottom = "";
283
+ toolbar.style.right = "";
284
+ }
285
+ }, positionInputBar = function(bounds) {
286
+ const inputBar = document.getElementById("claw-input-bar");
287
+ const viewportHeight = window.innerHeight;
288
+ const viewportWidth = window.innerWidth;
289
+ const MIN_EDGE_MARGIN = 16;
290
+ const SPACE_THRESHOLD = 80;
291
+ const INPUT_GAP = 8;
292
+ const barWidth = Math.max(240, Math.min(480, bounds.width));
293
+ inputBar.style.width = `${barWidth}px`;
294
+ let left = bounds.x;
295
+ if (left + barWidth > viewportWidth - MIN_EDGE_MARGIN) {
296
+ left = viewportWidth - MIN_EDGE_MARGIN - barWidth;
297
+ }
298
+ if (left < MIN_EDGE_MARGIN) left = MIN_EDGE_MARGIN;
299
+ inputBar.style.left = `${left}px`;
300
+ const spaceBelow = viewportHeight - (bounds.y + bounds.height);
301
+ const spaceAbove = bounds.y;
302
+ if (spaceBelow >= SPACE_THRESHOLD) {
303
+ inputBar.style.top = `${bounds.y + bounds.height + INPUT_GAP}px`;
304
+ inputBar.style.bottom = "";
305
+ } else if (spaceAbove >= SPACE_THRESHOLD) {
306
+ inputBar.style.top = "";
307
+ inputBar.style.bottom = `${viewportHeight - bounds.y + INPUT_GAP}px`;
308
+ } else {
309
+ inputBar.style.top = `${bounds.y + bounds.height + INPUT_GAP}px`;
310
+ inputBar.style.bottom = "";
311
+ }
312
+ }, showInputBar = function(bounds) {
313
+ const inputBar = document.getElementById("claw-input-bar");
314
+ const textarea2 = document.getElementById("claw-input-textarea");
315
+ inputBar.hidden = false;
316
+ positionInputBar(bounds);
317
+ requestAnimationFrame(() => {
318
+ inputBar.classList.add("claw-input-bar--visible");
319
+ });
320
+ textarea2.value = "";
321
+ textarea2.style.height = "auto";
322
+ textarea2.focus();
323
+ }, hideInputBar = function() {
324
+ const inputBar = document.getElementById("claw-input-bar");
325
+ inputBar.classList.remove("claw-input-bar--visible");
326
+ pastedImages.length = 0;
327
+ setTimeout(() => {
328
+ inputBar.hidden = true;
329
+ }, 100);
330
+ }, toggleViewportGroup = function() {
331
+ if (!viewportGroup) return;
332
+ viewportGroupOpen = !viewportGroupOpen;
333
+ if (viewportGroupOpen) {
334
+ viewportGroup.classList.add("claw-viewport-group--open");
335
+ viewportToggleBtn?.classList.add("claw-toolbar-btn--toggle-open");
336
+ } else {
337
+ viewportGroup.classList.remove("claw-viewport-group--open");
338
+ viewportToggleBtn?.classList.remove("claw-toolbar-btn--toggle-open");
339
+ }
340
+ }, updateViewportActiveState = function(preset) {
341
+ for (const [key, btn] of Object.entries(viewportButtons)) {
342
+ if (!btn) continue;
343
+ if (key === preset) {
344
+ btn.classList.add("claw-toolbar-btn--active");
345
+ } else {
346
+ btn.classList.remove("claw-toolbar-btn--active");
347
+ }
348
+ }
349
+ activeViewport = preset;
350
+ }, showTooltipForBtn = function(btn) {
351
+ if (!tooltipEl) return;
352
+ const text = btn.getAttribute("data-tooltip");
353
+ if (!text) return;
354
+ if (state.mode !== "inactive") return;
355
+ tooltipEl.textContent = text;
356
+ tooltipEl.hidden = false;
357
+ tooltipActiveBtn = btn;
358
+ const btnRect = btn.getBoundingClientRect();
359
+ const tooltipRect = tooltipEl.getBoundingClientRect();
360
+ const left = btnRect.left - tooltipRect.width - 8;
361
+ const top = btnRect.top + (btnRect.height - tooltipRect.height) / 2;
362
+ tooltipEl.style.left = `${Math.max(4, left)}px`;
363
+ tooltipEl.style.top = `${Math.max(4, top)}px`;
364
+ btn.setAttribute("aria-describedby", "claw-tooltip");
365
+ }, hideTooltip = function() {
366
+ if (!tooltipEl) return;
367
+ tooltipEl.hidden = true;
368
+ if (tooltipTimer) {
369
+ clearTimeout(tooltipTimer);
370
+ tooltipTimer = null;
371
+ }
372
+ if (tooltipActiveBtn) {
373
+ tooltipActiveBtn.removeAttribute("aria-describedby");
374
+ tooltipActiveBtn = null;
375
+ }
376
+ };
377
+ let state = { ...INITIAL_STATE };
378
+ let elemHoverRafPending = false;
379
+ let onModeChange = null;
380
+ const toolbar = document.getElementById("claw-toolbar");
381
+ const selectBtn = document.getElementById("claw-select-btn");
382
+ if (selectBtn) {
383
+ selectBtn.addEventListener("click", async (e) => {
384
+ e.stopPropagation();
385
+ if (state.mode === "inactive" || state.mode === "elem-idle" || state.mode === "elem-hovering" || state.mode === "elem-committed") {
386
+ hideInputBar();
387
+ const localRect = captureToolbarLocalRect();
388
+ const viewBounds = await window.claw?.activateSelection();
389
+ activateOverlaySurface(localRect, viewBounds);
390
+ dispatch({ type: "ACTIVATE_RECT" });
391
+ } else if (state.mode === "rect-idle" || state.mode === "rect-drawing" || state.mode === "rect-committed") {
392
+ hideInputBar();
393
+ dispatch({ type: "CANCEL" });
394
+ await window.claw?.deactivateSelection();
395
+ deactivateOverlaySurface();
396
+ }
397
+ });
398
+ }
399
+ const elemBtn = document.getElementById("claw-elem-btn");
400
+ if (elemBtn) {
401
+ elemBtn.addEventListener("click", async (e) => {
402
+ e.stopPropagation();
403
+ if (state.mode === "inactive" || state.mode === "rect-idle" || state.mode === "rect-drawing" || state.mode === "rect-committed") {
404
+ hideInputBar();
405
+ const localRect = captureToolbarLocalRect();
406
+ const viewBounds = await window.claw?.activateSelection();
407
+ activateOverlaySurface(localRect, viewBounds);
408
+ dispatch({ type: "ACTIVATE_ELEM" });
409
+ } else if (state.mode === "elem-idle" || state.mode === "elem-hovering" || state.mode === "elem-committed") {
410
+ hideInputBar();
411
+ dispatch({ type: "CANCEL" });
412
+ await window.claw?.deactivateSelection();
413
+ deactivateOverlaySurface();
414
+ }
415
+ });
416
+ }
417
+ document.addEventListener("mousedown", (e) => {
418
+ if (state.mode === "rect-idle") {
419
+ dispatch({ type: "MOUSE_DOWN", x: e.clientX, y: e.clientY });
420
+ }
421
+ });
422
+ document.addEventListener("mousemove", (e) => {
423
+ if (state.mode === "rect-drawing") {
424
+ dispatch({ type: "MOUSE_MOVE", x: e.clientX, y: e.clientY });
425
+ } else if ((state.mode === "elem-idle" || state.mode === "elem-hovering") && !elemHoverRafPending) {
426
+ elemHoverRafPending = true;
427
+ const x = e.clientX;
428
+ const y = e.clientY;
429
+ requestAnimationFrame(async () => {
430
+ elemHoverRafPending = false;
431
+ try {
432
+ const rect = await window.claw.getElementAtPoint(x, y);
433
+ if (rect) {
434
+ dispatch({ type: "ELEMENT_HOVER", rect });
435
+ }
436
+ } catch {
437
+ }
438
+ });
439
+ }
440
+ });
441
+ document.addEventListener("mouseup", (e) => {
442
+ if (state.mode === "rect-drawing") {
443
+ dispatch({ type: "MOUSE_UP", x: e.clientX, y: e.clientY });
444
+ }
445
+ });
446
+ document.addEventListener("click", (e) => {
447
+ if (state.mode === "elem-hovering") {
448
+ e.stopPropagation();
449
+ dispatch({ type: "ELEMENT_CLICK" });
450
+ }
451
+ });
452
+ document.addEventListener("keydown", async (e) => {
453
+ if (e.key === "Escape" && state.mode !== "inactive") {
454
+ hideInputBar();
455
+ dispatch({ type: "CANCEL" });
456
+ await window.claw?.deactivateSelection();
457
+ deactivateOverlaySurface();
458
+ }
459
+ });
460
+ const pastedImages = [];
461
+ const modelSelect = document.getElementById("claw-model-select");
462
+ const savedModel = localStorage.getItem("claw-model");
463
+ if (savedModel && modelSelect.querySelector(`option[value="${savedModel}"]`)) {
464
+ modelSelect.value = savedModel;
465
+ }
466
+ modelSelect.addEventListener("change", () => {
467
+ localStorage.setItem("claw-model", modelSelect.value);
468
+ });
469
+ const textarea = document.getElementById("claw-input-textarea");
470
+ const submitBtn = document.getElementById("claw-input-submit");
471
+ textarea.addEventListener("input", () => {
472
+ textarea.style.height = "auto";
473
+ const newHeight = Math.min(textarea.scrollHeight, 160);
474
+ textarea.style.height = `${newHeight}px`;
475
+ if (textarea.value.trim() || pastedImages.length > 0) {
476
+ submitBtn.classList.add("claw-input-bar__submit--enabled");
477
+ submitBtn.removeAttribute("disabled");
478
+ } else {
479
+ submitBtn.classList.remove("claw-input-bar__submit--enabled");
480
+ submitBtn.setAttribute("disabled", "");
481
+ }
482
+ });
483
+ textarea.addEventListener("paste", (e) => {
484
+ const items = e.clipboardData?.items;
485
+ if (!items) return;
486
+ for (const item of items) {
487
+ if (item.type.startsWith("image/")) {
488
+ e.preventDefault();
489
+ const blob = item.getAsFile();
490
+ if (!blob) continue;
491
+ const reader = new FileReader();
492
+ reader.onload = () => {
493
+ const dataUrl = reader.result;
494
+ const arrayBuf = Uint8Array.from(atob(dataUrl.split(",")[1]), (c) => c.charCodeAt(0)).buffer;
495
+ pastedImages.push({ dataUrl, buffer: arrayBuf });
496
+ const imageNum = pastedImages.length;
497
+ const pos = textarea.selectionStart;
498
+ const before = textarea.value.slice(0, pos);
499
+ const after = textarea.value.slice(pos);
500
+ const tag = `[Image #${imageNum}]`;
501
+ textarea.value = before + tag + after;
502
+ textarea.selectionStart = textarea.selectionEnd = pos + tag.length;
503
+ textarea.style.height = "auto";
504
+ textarea.style.height = `${Math.min(textarea.scrollHeight, 160)}px`;
505
+ submitBtn.classList.add("claw-input-bar__submit--enabled");
506
+ submitBtn.removeAttribute("disabled");
507
+ textarea.focus();
508
+ };
509
+ reader.readAsDataURL(blob);
510
+ }
511
+ }
512
+ });
513
+ textarea.addEventListener("keydown", (e) => {
514
+ if (e.key === "Enter" && !e.shiftKey) {
515
+ e.preventDefault();
516
+ handleSubmit();
517
+ }
518
+ });
519
+ async function handleSubmit() {
520
+ const instruction = textarea.value.trim();
521
+ if (!instruction && pastedImages.length === 0 || !state.selectionBounds) return;
522
+ const bounds = state.selectionBounds;
523
+ const [screenshot, dom] = await Promise.all([
524
+ window.claw.captureScreenshot(bounds),
525
+ window.claw.extractDom(bounds)
526
+ ]);
527
+ const referenceImages = [];
528
+ for (let i = 0; i < pastedImages.length; i++) {
529
+ if (instruction.includes(`[Image #${i + 1}]`)) {
530
+ referenceImages.push(Buffer.from(new Uint8Array(pastedImages[i].buffer)));
531
+ }
532
+ }
533
+ if (pastedImages.length > 0 && referenceImages.length === 0 && !/\[Image #\d+\]/.test(instruction)) {
534
+ for (const img of pastedImages) {
535
+ referenceImages.push(Buffer.from(new Uint8Array(img.buffer)));
536
+ }
537
+ }
538
+ await window.claw.submitInstruction({
539
+ instruction: instruction || "Make the changes shown in the reference image(s)",
540
+ screenshot,
541
+ dom,
542
+ bounds,
543
+ referenceImages: referenceImages.length > 0 ? referenceImages : void 0,
544
+ model: modelSelect.value
545
+ });
546
+ pastedImages.length = 0;
547
+ hideInputBar();
548
+ dispatch({ type: "CANCEL" });
549
+ await window.claw.deactivateSelection();
550
+ deactivateOverlaySurface();
551
+ }
552
+ submitBtn.addEventListener("click", handleSubmit);
553
+ document.addEventListener("claw:selection-committed", ((e) => {
554
+ showInputBar(e.detail.bounds);
555
+ }));
556
+ __vitePreload(async () => {
557
+ const { showToast, dismissToast } = await import("./toast-CLlgwMU_.js");
558
+ return { showToast, dismissToast };
559
+ }, true ? [] : void 0, import.meta.url).then(({ showToast, dismissToast }) => {
560
+ if (window.claw?.onToastShow) {
561
+ window.claw.onToastShow((data) => showToast(document, data));
562
+ }
563
+ if (window.claw?.onToastDismiss) {
564
+ window.claw.onToastDismiss((data) => dismissToast(document, data.id));
565
+ }
566
+ });
567
+ if (window.claw?.onModeChange) {
568
+ window.claw.onModeChange((mode) => {
569
+ console.debug("[claw-overlay] mode:", mode);
570
+ });
571
+ }
572
+ if (window.claw?.onPrefillInstruction) {
573
+ window.claw.onPrefillInstruction(async (data) => {
574
+ const ta = document.getElementById("claw-input-textarea");
575
+ if (ta) {
576
+ ta.value = data.instruction;
577
+ ta.dispatchEvent(new Event("input"));
578
+ }
579
+ const localRect = captureToolbarLocalRect();
580
+ const viewBounds = await window.claw?.activateSelection();
581
+ activateOverlaySurface(localRect, viewBounds);
582
+ dispatch({ type: "ACTIVATE_RECT" });
583
+ const inputBar = document.getElementById("claw-input-bar");
584
+ inputBar.hidden = false;
585
+ inputBar.style.left = "50%";
586
+ inputBar.style.transform = "translateX(-50%)";
587
+ inputBar.style.top = `${Math.round(window.innerHeight * 0.6)}px`;
588
+ inputBar.style.bottom = "";
589
+ requestAnimationFrame(() => {
590
+ inputBar.classList.add("claw-input-bar--visible");
591
+ });
592
+ if (ta) {
593
+ ta.focus();
594
+ }
595
+ });
596
+ }
597
+ const toolbarHandle = document.querySelector(".claw-toolbar-handle");
598
+ if (toolbarHandle) {
599
+ let isDragging = false;
600
+ let lastScreenX = 0;
601
+ let lastScreenY = 0;
602
+ toolbarHandle.addEventListener("mousedown", (e) => {
603
+ isDragging = true;
604
+ lastScreenX = e.screenX;
605
+ lastScreenY = e.screenY;
606
+ toolbarHandle.style.cursor = "grabbing";
607
+ e.preventDefault();
608
+ });
609
+ document.addEventListener("mousemove", (e) => {
610
+ if (!isDragging) return;
611
+ const dx = e.screenX - lastScreenX;
612
+ const dy = e.screenY - lastScreenY;
613
+ lastScreenX = e.screenX;
614
+ lastScreenY = e.screenY;
615
+ if (dx !== 0 || dy !== 0) {
616
+ window.claw.dragToolbar(dx, dy);
617
+ }
618
+ });
619
+ document.addEventListener("mouseup", () => {
620
+ if (!isDragging) return;
621
+ isDragging = false;
622
+ toolbarHandle.style.cursor = "";
623
+ window.claw.dragToolbar(0, 0).then((pos) => {
624
+ localStorage.setItem("claw-toolbar-pos", JSON.stringify(pos));
625
+ });
626
+ });
627
+ const savedToolbarPos = localStorage.getItem("claw-toolbar-pos");
628
+ if (savedToolbarPos) {
629
+ try {
630
+ const { x, y } = JSON.parse(savedToolbarPos);
631
+ if (typeof x === "number" && typeof y === "number") {
632
+ window.claw.setToolbarPosition(x, y);
633
+ }
634
+ } catch {
635
+ }
636
+ }
637
+ }
638
+ let activeViewport = "desktop";
639
+ let viewportGroupOpen = false;
640
+ const viewportToggleBtn = document.getElementById("claw-viewport-toggle-btn");
641
+ const viewportGroup = document.getElementById("claw-viewport-group");
642
+ const viewportButtons = {
643
+ desktop: document.getElementById("claw-viewport-desktop-btn"),
644
+ tablet: document.getElementById("claw-viewport-tablet-btn"),
645
+ mobile: document.getElementById("claw-viewport-mobile-btn")
646
+ };
647
+ if (viewportToggleBtn) {
648
+ viewportToggleBtn.addEventListener("click", (e) => {
649
+ e.stopPropagation();
650
+ toggleViewportGroup();
651
+ });
652
+ }
653
+ for (const [preset, btn] of Object.entries(viewportButtons)) {
654
+ if (!btn) continue;
655
+ btn.addEventListener("click", async (e) => {
656
+ e.stopPropagation();
657
+ if (activeViewport === preset) return;
658
+ updateViewportActiveState(preset);
659
+ await window.claw.setViewport(preset);
660
+ if (viewportGroupOpen) toggleViewportGroup();
661
+ });
662
+ }
663
+ if (window.claw?.onViewportChanged) {
664
+ window.claw.onViewportChanged((data) => {
665
+ updateViewportActiveState(data.preset);
666
+ });
667
+ }
668
+ const tooltipEl = document.getElementById("claw-tooltip");
669
+ let tooltipTimer = null;
670
+ let tooltipActiveBtn = null;
671
+ const tooltipButtons = document.querySelectorAll("[data-tooltip]");
672
+ for (const btn of tooltipButtons) {
673
+ btn.addEventListener("mouseenter", () => {
674
+ tooltipTimer = setTimeout(() => {
675
+ showTooltipForBtn(btn);
676
+ }, 400);
677
+ });
678
+ btn.addEventListener("mouseleave", () => {
679
+ hideTooltip();
680
+ });
681
+ }
682
+ onModeChange = hideTooltip;
683
+ if (window.claw?.onSiteLoaded) {
684
+ window.claw.onSiteLoaded(() => {
685
+ const loadingEl = document.getElementById("claw-loading");
686
+ if (loadingEl) loadingEl.classList.add("claw-loading--hidden");
687
+ });
688
+ }
689
+ }