@useclickly/react 1.0.1 → 1.0.3

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.cjs CHANGED
@@ -1373,6 +1373,18 @@ function Icon({
1373
1373
  }
1374
1374
  );
1375
1375
  }
1376
+ var IconFreeze = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { size: 15, children: [
1377
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "22" }),
1378
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
1379
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "5", y1: "5", x2: "19", y2: "19" }),
1380
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "19", y1: "5", x2: "5", y2: "19" }),
1381
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "2", fill: "currentColor", stroke: "none" })
1382
+ ] });
1383
+ var IconInfo = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { size: 14, children: [
1384
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1385
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "8", x2: "12", y2: "8", strokeWidth: "2.5" }),
1386
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "12", x2: "12", y2: "16" })
1387
+ ] });
1376
1388
  var IconCursor = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 4l6 16 2-7 7-2z" }) });
1377
1389
  var IconLayers = () => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { children: [
1378
1390
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2l9 5-9 5-9-5 9-5z" }),
@@ -1591,7 +1603,46 @@ function AnnotationCard({
1591
1603
 
1592
1604
  // packages/react/src/internal/Toolbar.tsx
1593
1605
  var import_jsx_runtime4 = require("react/jsx-runtime");
1594
- var TOOLBAR_SIZE = { width: 320, height: 44 };
1606
+ var TOOLBAR_SIZE = { width: 360, height: 44 };
1607
+ var SHORTCUTS = [
1608
+ { keys: ["\u2318", "\u21E7", "F"], label: "Toggle toolbar" },
1609
+ { keys: ["1"], label: "Single select mode" },
1610
+ { keys: ["2"], label: "Multi select mode" },
1611
+ { keys: ["3"], label: "Area drag mode" },
1612
+ { keys: ["\u21B5"], label: "Annotate pinned elements" },
1613
+ { keys: ["Esc"], label: "Cancel / clear / close" },
1614
+ { keys: ["\u2318", "\u21B5"], label: "Submit annotation" },
1615
+ { keys: ["C"], label: "Copy all annotations" },
1616
+ { keys: ["X"], label: "Clear all annotations" }
1617
+ ];
1618
+ function ShortcutsPanel() {
1619
+ const [visible, setVisible] = (0, import_react7.useState)(false);
1620
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1621
+ "span",
1622
+ {
1623
+ className: "clickly-tip shortcuts-trigger",
1624
+ onMouseEnter: () => setVisible(true),
1625
+ onMouseLeave: () => setVisible(false),
1626
+ children: [
1627
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1628
+ "button",
1629
+ {
1630
+ className: "clickly-btn icon-only",
1631
+ "aria-label": "Show keyboard shortcuts",
1632
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(IconInfo, {})
1633
+ }
1634
+ ),
1635
+ visible && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "shortcuts-panel", role: "tooltip", children: [
1636
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "shortcuts-title", children: "Keyboard shortcuts" }),
1637
+ SHORTCUTS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "shortcuts-row", children: [
1638
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "shortcuts-label", children: s.label }),
1639
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "shortcuts-keys", children: s.keys.map((k) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("kbd", { children: k }, k)) })
1640
+ ] }, s.label))
1641
+ ] })
1642
+ ]
1643
+ }
1644
+ );
1645
+ }
1595
1646
  function Tip({
1596
1647
  label,
1597
1648
  shortcut,
@@ -1612,7 +1663,38 @@ function Toolbar({ engine, onCollapse }) {
1612
1663
  const outputDetail = useSettings((s) => s.outputDetail);
1613
1664
  const [showSettings, setShowSettings] = (0, import_react7.useState)(false);
1614
1665
  const [showList, setShowList] = (0, import_react7.useState)(false);
1666
+ const [frozen, setFrozen] = (0, import_react7.useState)(false);
1615
1667
  const anchorRef = (0, import_react7.useRef)(null);
1668
+ (0, import_react7.useEffect)(() => {
1669
+ const STYLE_ID = "clickly-freeze-animations";
1670
+ const gsap = window.gsap;
1671
+ if (frozen) {
1672
+ if (!document.getElementById(STYLE_ID)) {
1673
+ const el = document.createElement("style");
1674
+ el.id = STYLE_ID;
1675
+ el.textContent = `
1676
+ *, *::before, *::after {
1677
+ animation-play-state: paused !important;
1678
+ transition-duration: 0ms !important;
1679
+ transition-delay: 0ms !important;
1680
+ }
1681
+ `;
1682
+ document.head.appendChild(el);
1683
+ }
1684
+ if (gsap?.globalTimeline) {
1685
+ gsap.globalTimeline.pause();
1686
+ }
1687
+ } else {
1688
+ document.getElementById(STYLE_ID)?.remove();
1689
+ if (gsap?.globalTimeline) {
1690
+ gsap.globalTimeline.resume();
1691
+ }
1692
+ }
1693
+ return () => {
1694
+ document.getElementById(STYLE_ID)?.remove();
1695
+ if (gsap?.globalTimeline) gsap.globalTimeline.resume();
1696
+ };
1697
+ }, [frozen]);
1616
1698
  const { position, handleProps } = useDraggable(
1617
1699
  {
1618
1700
  x: Math.max(8, window.innerWidth - TOOLBAR_SIZE.width - 16),
@@ -1695,6 +1777,16 @@ function Toolbar({ engine, onCollapse }) {
1695
1777
  ) }),
1696
1778
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "divider" })
1697
1779
  ] }),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tip, { label: frozen ? "Unfreeze animations" : "Freeze animations", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1781
+ "button",
1782
+ {
1783
+ className: `clickly-btn icon-only${frozen ? " is-freeze" : ""}`,
1784
+ onClick: () => setFrozen((v) => !v),
1785
+ "aria-label": frozen ? "Unfreeze page animations" : "Freeze page animations",
1786
+ "aria-pressed": frozen,
1787
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(IconFreeze, {})
1788
+ }
1789
+ ) }),
1698
1790
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tip, { label: "Annotations", shortcut: "L", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1699
1791
  "button",
1700
1792
  {
@@ -1728,6 +1820,7 @@ function Toolbar({ engine, onCollapse }) {
1728
1820
  }
1729
1821
  ) }),
1730
1822
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "divider" }),
1823
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ShortcutsPanel, {}),
1731
1824
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tip, { label: "Settings", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1732
1825
  "button",
1733
1826
  {
@@ -2194,24 +2287,36 @@ function pinLabel(annotation) {
2194
2287
  const tag = raw.split(/[.#\s]/)[0] ?? "";
2195
2288
  return (TAG_LABELS3[tag] ?? tag) || "element";
2196
2289
  }
2290
+ function parseStyles(raw) {
2291
+ if (!raw) return [];
2292
+ return raw.split(";").map((s) => s.trim()).filter(Boolean).map((s) => {
2293
+ const colon = s.indexOf(":");
2294
+ if (colon === -1) return null;
2295
+ return [s.slice(0, colon).trim(), s.slice(colon + 1).trim()];
2296
+ }).filter(Boolean);
2297
+ }
2197
2298
  function Pin({ number, annotation }) {
2198
2299
  const remove = useAnnotations((s) => s.remove);
2199
2300
  const update = useAnnotations((s) => s.update);
2200
2301
  const [hovered, setHovered] = (0, import_react9.useState)(false);
2201
2302
  const [editing, setEditing] = (0, import_react9.useState)(false);
2202
2303
  const [draft, setDraft] = (0, import_react9.useState)(annotation.comment);
2304
+ const [showStyles, setShowStyles] = (0, import_react9.useState)(false);
2203
2305
  const taRef = (0, import_react9.useRef)(null);
2204
2306
  const editRef = (0, import_react9.useRef)(null);
2205
- const pos = resolvePosition(annotation);
2206
- if (!pos) return null;
2307
+ const styleEntries = parseStyles(annotation.computedStyles);
2207
2308
  const label = pinLabel(annotation);
2309
+ const headerLabel = annotation.isMultiSelect ? `${label} (multi-select)` : `${label}: "${annotation.elementPath}"`;
2208
2310
  const openEdit = () => {
2209
2311
  setDraft(annotation.comment);
2210
2312
  setEditing(true);
2211
2313
  setHovered(false);
2212
2314
  requestAnimationFrame(() => taRef.current?.focus());
2213
2315
  };
2214
- const closeEdit = () => setEditing(false);
2316
+ const closeEdit = () => {
2317
+ setEditing(false);
2318
+ setShowStyles(false);
2319
+ };
2215
2320
  const save = () => {
2216
2321
  const trimmed = draft.trim();
2217
2322
  if (trimmed) update(annotation.id, { comment: trimmed });
@@ -2230,6 +2335,27 @@ function Pin({ number, annotation }) {
2230
2335
  window.addEventListener("pointerdown", onDown, true);
2231
2336
  return () => window.removeEventListener("pointerdown", onDown, true);
2232
2337
  }, [editing]);
2338
+ (0, import_react9.useEffect)(() => {
2339
+ if (!editing) return;
2340
+ let el = null;
2341
+ if (annotation.elementPath) {
2342
+ try {
2343
+ el = document.querySelector(annotation.elementPath);
2344
+ } catch {
2345
+ }
2346
+ }
2347
+ if (!el) return;
2348
+ const prevOutline = el.style.outline;
2349
+ const prevOffset = el.style.outlineOffset;
2350
+ el.style.outline = "2px solid #10b981";
2351
+ el.style.outlineOffset = "3px";
2352
+ return () => {
2353
+ el.style.outline = prevOutline;
2354
+ el.style.outlineOffset = prevOffset;
2355
+ };
2356
+ }, [editing, annotation.elementPath]);
2357
+ const pos = resolvePosition(annotation);
2358
+ if (!pos) return null;
2233
2359
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2234
2360
  "div",
2235
2361
  {
@@ -2260,21 +2386,42 @@ function Pin({ number, annotation }) {
2260
2386
  className: "pin-edit",
2261
2387
  onClick: (e) => e.stopPropagation(),
2262
2388
  children: [
2263
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "pin-edit-header", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "pin-edit-label", children: [
2264
- label,
2265
- ": ",
2266
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "pin-edit-path", children: annotation.elementPath })
2267
- ] }) }),
2389
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2390
+ "div",
2391
+ {
2392
+ className: "popup-header",
2393
+ role: "button",
2394
+ "aria-expanded": showStyles,
2395
+ onClick: (e) => {
2396
+ e.stopPropagation();
2397
+ setShowStyles((v) => !v);
2398
+ },
2399
+ children: [
2400
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "popup-chevron", children: showStyles ? "\u25BE" : "\u203A" }),
2401
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "popup-label", children: headerLabel })
2402
+ ]
2403
+ }
2404
+ ),
2405
+ showStyles && styleEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "popup-styles", children: [
2406
+ styleEntries.map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "style-row", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "style-key", children: k }),
2408
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "style-val", children: v })
2409
+ ] }, k)),
2410
+ annotation.suggestedCss && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "style-hint", style: { color: "#7c3aed", borderTopColor: "rgba(124,58,237,0.2)" }, children: [
2411
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "Suggested changes:" }),
2412
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("br", {}),
2413
+ annotation.suggestedCss
2414
+ ] })
2415
+ ] }),
2268
2416
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2269
2417
  "textarea",
2270
2418
  {
2271
2419
  ref: taRef,
2272
- className: "pin-edit-textarea",
2273
2420
  value: draft,
2274
2421
  onChange: (e) => setDraft(e.target.value),
2275
2422
  onKeyDown,
2276
- placeholder: "Describe the issue\u2026",
2277
- rows: 3
2423
+ placeholder: "Describe the issue\u2026 (\u2318/Ctrl + Enter to save)",
2424
+ "aria-label": "Annotation comment"
2278
2425
  }
2279
2426
  ),
2280
2427
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "pin-edit-actions", children: [
@@ -2287,9 +2434,9 @@ function Pin({ number, annotation }) {
2287
2434
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconTrash, {})
2288
2435
  }
2289
2436
  ),
2290
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "pin-edit-right", children: [
2291
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "pin-edit-cancel", onClick: closeEdit, children: "Cancel" }),
2292
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "pin-edit-save", onClick: save, children: "Save" })
2437
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "row", style: { margin: 0, flex: 1, justifyContent: "flex-end" }, children: [
2438
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "ghost", onClick: closeEdit, children: "Cancel" }),
2439
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { className: "primary", onClick: save, children: "Save" })
2293
2440
  ] })
2294
2441
  ] })
2295
2442
  ]
@@ -2311,10 +2458,7 @@ function resolvePosition(a) {
2311
2458
  }
2312
2459
  }
2313
2460
  if (a.boundingBox) {
2314
- return {
2315
- x: a.boundingBox.x + a.boundingBox.width - 11,
2316
- y: a.boundingBox.y - 11
2317
- };
2461
+ return { x: a.boundingBox.x + a.boundingBox.width - 11, y: a.boundingBox.y - 11 };
2318
2462
  }
2319
2463
  return null;
2320
2464
  }
@@ -2538,6 +2682,14 @@ var REACT_UI_CSS = `
2538
2682
  .clickly-btn.is-active:hover { background: #0284c7; }
2539
2683
  .clickly-btn[disabled] { opacity: 0.28; cursor: not-allowed; pointer-events: none; }
2540
2684
 
2685
+ /* Freeze-animations active state \u2014 icy blue */
2686
+ .clickly-btn.is-freeze {
2687
+ background: rgba(99, 179, 237, 0.18);
2688
+ color: #63b3ed;
2689
+ box-shadow: 0 0 0 1px rgba(99,179,237,0.35), 0 2px 8px rgba(99,179,237,0.2);
2690
+ }
2691
+ .clickly-btn.is-freeze:hover { background: rgba(99, 179, 237, 0.26); }
2692
+
2541
2693
  .clickly-btn.icon-only {
2542
2694
  width: 32px;
2543
2695
  padding: 0;
@@ -2615,6 +2767,91 @@ var REACT_UI_CSS = `
2615
2767
  color: #94a3b8;
2616
2768
  }
2617
2769
 
2770
+ /* \u2500\u2500\u2500 Shortcuts panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
2771
+
2772
+ .shortcuts-trigger {
2773
+ position: relative;
2774
+ display: inline-flex;
2775
+ align-items: center;
2776
+ justify-content: center;
2777
+ }
2778
+
2779
+ .shortcuts-panel {
2780
+ position: absolute;
2781
+ bottom: calc(100% + 12px);
2782
+ left: 50%;
2783
+ transform: translateX(-50%);
2784
+ width: 260px;
2785
+ background: rgba(9, 14, 28, 0.97);
2786
+ border: 1px solid rgba(255,255,255,0.08);
2787
+ border-radius: 12px;
2788
+ box-shadow: 0 16px 40px rgba(0,0,0,0.45);
2789
+ padding: 10px;
2790
+ z-index: 10;
2791
+ animation: clickly-fade-in 100ms ease-out;
2792
+ pointer-events: none;
2793
+ }
2794
+
2795
+ /* Arrow pointing down */
2796
+ .shortcuts-panel::after {
2797
+ content: "";
2798
+ position: absolute;
2799
+ top: 100%;
2800
+ left: 50%;
2801
+ transform: translateX(-50%);
2802
+ border: 6px solid transparent;
2803
+ border-top-color: rgba(9, 14, 28, 0.97);
2804
+ }
2805
+
2806
+ .shortcuts-title {
2807
+ font: 600 11px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
2808
+ color: #64748b;
2809
+ text-transform: uppercase;
2810
+ letter-spacing: 0.06em;
2811
+ padding: 2px 4px 8px;
2812
+ border-bottom: 1px solid rgba(255,255,255,0.06);
2813
+ margin-bottom: 6px;
2814
+ }
2815
+
2816
+ .shortcuts-row {
2817
+ display: flex;
2818
+ align-items: center;
2819
+ justify-content: space-between;
2820
+ padding: 4px 4px;
2821
+ border-radius: 6px;
2822
+ gap: 8px;
2823
+ }
2824
+ .shortcuts-row:hover { background: rgba(255,255,255,0.04); }
2825
+
2826
+ .shortcuts-label {
2827
+ font: 12px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
2828
+ color: #94a3b8;
2829
+ flex: 1;
2830
+ min-width: 0;
2831
+ }
2832
+
2833
+ .shortcuts-keys {
2834
+ display: flex;
2835
+ gap: 3px;
2836
+ align-items: center;
2837
+ flex-shrink: 0;
2838
+ }
2839
+
2840
+ .shortcuts-keys kbd {
2841
+ display: inline-flex;
2842
+ align-items: center;
2843
+ justify-content: center;
2844
+ min-width: 20px;
2845
+ height: 20px;
2846
+ padding: 0 5px;
2847
+ background: rgba(255,255,255,0.08);
2848
+ border: 1px solid rgba(255,255,255,0.10);
2849
+ border-bottom-width: 2px;
2850
+ border-radius: 5px;
2851
+ font: 11px/1 ui-monospace, "SF Mono", Menlo, monospace;
2852
+ color: #e2e8f0;
2853
+ }
2854
+
2618
2855
  /* \u2500\u2500\u2500 Popup & popovers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
2619
2856
 
2620
2857
  .clickly-popup, .clickly-popover {
@@ -2638,8 +2875,10 @@ var REACT_UI_CSS = `
2638
2875
  flex-direction: column;
2639
2876
  }
2640
2877
 
2641
- /* Collapsible header row \u2014 shows element label + CSS toggle */
2642
- .clickly-popup .popup-header {
2878
+ /* \u2500\u2500\u2500 Shared inner styles \u2014 apply to both popup and pin-edit \u2500\u2500\u2500 */
2879
+
2880
+ .clickly-popup .popup-header,
2881
+ .pin-edit .popup-header {
2643
2882
  display: flex;
2644
2883
  align-items: center;
2645
2884
  gap: 5px;
@@ -2653,9 +2892,11 @@ var REACT_UI_CSS = `
2653
2892
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
2654
2893
  transition: background 80ms ease;
2655
2894
  }
2656
- .clickly-popup .popup-header:hover { background: #f1f5f9; }
2895
+ .clickly-popup .popup-header:hover,
2896
+ .pin-edit .popup-header:hover { background: #f1f5f9; }
2657
2897
 
2658
- .clickly-popup .popup-chevron {
2898
+ .clickly-popup .popup-chevron,
2899
+ .pin-edit .popup-chevron {
2659
2900
  font-size: 12px;
2660
2901
  color: #94a3b8;
2661
2902
  flex-shrink: 0;
@@ -2663,7 +2904,8 @@ var REACT_UI_CSS = `
2663
2904
  text-align: center;
2664
2905
  }
2665
2906
 
2666
- .clickly-popup .popup-label {
2907
+ .clickly-popup .popup-label,
2908
+ .pin-edit .popup-label {
2667
2909
  flex: 1;
2668
2910
  overflow: hidden;
2669
2911
  white-space: nowrap;
@@ -2701,7 +2943,8 @@ var REACT_UI_CSS = `
2701
2943
  }
2702
2944
 
2703
2945
  /* Computed-styles panel */
2704
- .clickly-popup .popup-styles {
2946
+ .clickly-popup .popup-styles,
2947
+ .pin-edit .popup-styles {
2705
2948
  margin-bottom: 8px;
2706
2949
  padding: 8px;
2707
2950
  background: #f8fafc;
@@ -2714,7 +2957,8 @@ var REACT_UI_CSS = `
2714
2957
  overscroll-behavior: contain;
2715
2958
  }
2716
2959
 
2717
- .clickly-popup .style-row {
2960
+ .clickly-popup .style-row,
2961
+ .pin-edit .style-row {
2718
2962
  display: flex;
2719
2963
  align-items: center;
2720
2964
  gap: 6px;
@@ -2724,17 +2968,27 @@ var REACT_UI_CSS = `
2724
2968
  transition: background 80ms ease;
2725
2969
  }
2726
2970
 
2727
- .clickly-popup .style-row--changed {
2971
+ .clickly-popup .style-row--changed,
2972
+ .pin-edit .style-row--changed {
2728
2973
  background: rgba(245, 158, 11, 0.10);
2729
2974
  }
2730
2975
 
2731
- .clickly-popup .style-key {
2976
+ .clickly-popup .style-key,
2977
+ .pin-edit .style-key {
2732
2978
  color: #7c3aed;
2733
2979
  flex-shrink: 0;
2734
2980
  min-width: 90px;
2735
2981
  font-size: 11px;
2736
2982
  }
2737
2983
 
2984
+ .clickly-popup .style-val,
2985
+ .pin-edit .style-val {
2986
+ color: #0f172a;
2987
+ font-size: 11px;
2988
+ word-break: break-all;
2989
+ flex: 1;
2990
+ }
2991
+
2738
2992
  /* Editable value input \u2014 live CSS preview */
2739
2993
  .clickly-popup .style-val-input {
2740
2994
  flex: 1;
@@ -2773,8 +3027,9 @@ var REACT_UI_CSS = `
2773
3027
  background: rgba(245,158,11,0.12);
2774
3028
  }
2775
3029
 
2776
- /* Hint text at bottom of CSS panel when edits exist */
2777
- .clickly-popup .style-hint {
3030
+ /* Hint text at bottom of CSS panel */
3031
+ .clickly-popup .style-hint,
3032
+ .pin-edit .style-hint {
2778
3033
  margin-top: 6px;
2779
3034
  padding-top: 6px;
2780
3035
  border-top: 1px solid #e2e8f0;
@@ -2784,7 +3039,8 @@ var REACT_UI_CSS = `
2784
3039
  line-height: 1.4;
2785
3040
  }
2786
3041
 
2787
- .clickly-popup textarea {
3042
+ .clickly-popup textarea,
3043
+ .pin-edit textarea {
2788
3044
  width: 100%;
2789
3045
  min-height: 64px;
2790
3046
  max-height: 160px;
@@ -2795,33 +3051,40 @@ var REACT_UI_CSS = `
2795
3051
  font: inherit;
2796
3052
  color: inherit;
2797
3053
  }
2798
- .clickly-popup textarea:focus {
3054
+ .clickly-popup textarea:focus,
3055
+ .pin-edit textarea:focus {
2799
3056
  outline: none;
2800
3057
  border-color: #0ea5e9;
2801
3058
  box-shadow: 0 0 0 3px rgba(14,165,233,0.18);
2802
3059
  }
2803
3060
 
2804
- .clickly-popup .row {
3061
+ .clickly-popup .row,
3062
+ .pin-edit .row {
2805
3063
  display: flex;
2806
3064
  justify-content: flex-end;
2807
3065
  gap: 6px;
2808
3066
  margin-top: 10px;
2809
3067
  }
2810
3068
 
2811
- .clickly-popup .row .ghost {
3069
+ .clickly-popup .row .ghost,
3070
+ .pin-edit .row .ghost {
2812
3071
  background: transparent;
2813
3072
  color: #475569;
2814
3073
  border: 1px solid #e2e8f0;
2815
3074
  }
2816
- .clickly-popup .row .ghost:hover { background: #f8fafc; }
3075
+ .clickly-popup .row .ghost:hover,
3076
+ .pin-edit .row .ghost:hover { background: #f8fafc; }
2817
3077
 
2818
- .clickly-popup .row .primary {
3078
+ .clickly-popup .row .primary,
3079
+ .pin-edit .row .primary {
2819
3080
  background: #0ea5e9;
2820
3081
  color: #fff;
2821
3082
  border: none;
2822
3083
  }
2823
- .clickly-popup .row .primary:hover { background: #0284c7; }
2824
- .clickly-popup .row button {
3084
+ .clickly-popup .row .primary:hover,
3085
+ .pin-edit .row .primary:hover { background: #0284c7; }
3086
+ .clickly-popup .row button,
3087
+ .pin-edit .row button {
2825
3088
  height: 28px;
2826
3089
  padding: 0 12px;
2827
3090
  border-radius: 6px;
@@ -3102,119 +3365,77 @@ var REACT_UI_CSS = `
3102
3365
  overflow: hidden;
3103
3366
  }
3104
3367
 
3105
- /* \u2500\u2500\u2500 Pin edit popup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
3368
+ /* \u2500\u2500\u2500 Pin edit popup \u2014 same white card as .clickly-popup \u2500\u2500\u2500\u2500\u2500\u2500 */
3106
3369
 
3107
3370
  .pin-edit {
3371
+ /* Positioning: floats to the LEFT of the pin */
3108
3372
  position: absolute;
3109
- right: calc(100% + 10px);
3373
+ right: calc(100% + 12px);
3110
3374
  top: 50%;
3111
3375
  transform: translateY(-50%);
3112
- width: 260px;
3376
+ /* Appearance: identical to .clickly-popup */
3377
+ width: 300px;
3378
+ padding: 12px;
3113
3379
  background: #fff;
3114
- border-radius: 12px;
3115
- box-shadow: 0 12px 40px rgba(2,6,23,0.20), 0 0 0 1px rgba(15,23,42,0.07);
3116
- font: 13px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
3117
3380
  color: #0f172a;
3381
+ border-radius: 10px;
3382
+ box-shadow: 0 12px 32px rgba(2,6,23,0.18), 0 0 0 1px rgba(15,23,42,0.06);
3383
+ font: 13px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
3118
3384
  text-align: left;
3119
3385
  cursor: default;
3120
3386
  z-index: 11;
3121
3387
  animation: clickly-fade-in 120ms cubic-bezier(0.16,1,0.3,1);
3388
+ /* Allow inner popup-styles to scroll */
3389
+ max-height: 80vh;
3122
3390
  overflow: hidden;
3391
+ display: flex;
3392
+ flex-direction: column;
3123
3393
  }
3124
3394
 
3125
- .pin-edit-header {
3126
- padding: 10px 12px 8px;
3127
- border-bottom: 1px solid #f1f5f9;
3128
- }
3129
-
3130
- .pin-edit-label {
3131
- font-size: 11.5px;
3132
- font-weight: 600;
3133
- color: #475569;
3134
- }
3135
-
3136
- .pin-edit-path {
3137
- font-family: ui-monospace, "SF Mono", Menlo, monospace;
3138
- font-weight: 400;
3139
- color: #94a3b8;
3140
- font-size: 10.5px;
3141
- overflow: hidden;
3142
- white-space: nowrap;
3143
- text-overflow: ellipsis;
3144
- display: inline-block;
3145
- max-width: 160px;
3146
- vertical-align: bottom;
3147
- }
3148
-
3149
- .pin-edit-textarea {
3150
- display: block;
3395
+ /* Reuse .clickly-popup textarea inside pin-edit */
3396
+ .pin-edit textarea {
3151
3397
  width: 100%;
3152
- min-height: 72px;
3153
- padding: 10px 12px;
3154
- border: none;
3155
- border-bottom: 1px solid #f1f5f9;
3398
+ min-height: 64px;
3399
+ max-height: 120px;
3400
+ padding: 8px;
3401
+ border: 1px solid #e2e8f0;
3402
+ border-radius: 6px;
3156
3403
  resize: vertical;
3157
- font: 13px/1.5 inherit;
3158
- color: #0f172a;
3404
+ font: inherit;
3405
+ color: inherit;
3159
3406
  background: #fff;
3160
3407
  box-sizing: border-box;
3161
3408
  }
3162
- .pin-edit-textarea:focus {
3409
+ .pin-edit textarea:focus {
3163
3410
  outline: none;
3164
- background: #f8fafc;
3411
+ border-color: #0ea5e9;
3412
+ box-shadow: 0 0 0 3px rgba(14,165,233,0.18);
3165
3413
  }
3166
3414
 
3415
+ /* Actions row */
3167
3416
  .pin-edit-actions {
3168
3417
  display: flex;
3169
3418
  align-items: center;
3170
- justify-content: space-between;
3171
- padding: 8px 10px;
3172
- gap: 6px;
3173
- }
3174
-
3175
- .pin-edit-right {
3176
- display: flex;
3177
3419
  gap: 6px;
3420
+ margin-top: 10px;
3178
3421
  }
3179
3422
 
3180
3423
  .pin-edit-delete {
3181
3424
  display: grid;
3182
3425
  place-items: center;
3183
- width: 30px;
3184
- height: 30px;
3426
+ width: 28px;
3427
+ height: 28px;
3428
+ flex-shrink: 0;
3185
3429
  background: transparent;
3186
3430
  border: 1px solid #fee2e2;
3187
- border-radius: 8px;
3431
+ border-radius: 6px;
3188
3432
  color: #ef4444;
3189
3433
  cursor: pointer;
3190
3434
  padding: 0;
3191
3435
  transition: background 100ms, border-color 100ms;
3192
3436
  }
3193
3437
  .pin-edit-delete:hover { background: #fef2f2; border-color: #fca5a5; }
3194
- .pin-edit-delete svg { width: 14px; height: 14px; }
3195
-
3196
- .pin-edit-cancel, .pin-edit-save {
3197
- height: 30px;
3198
- padding: 0 12px;
3199
- border-radius: 8px;
3200
- font: 12px/1 inherit;
3201
- font-weight: 500;
3202
- cursor: pointer;
3203
- border: none;
3204
- transition: background 100ms;
3205
- }
3206
-
3207
- .pin-edit-cancel {
3208
- background: #f1f5f9;
3209
- color: #475569;
3210
- }
3211
- .pin-edit-cancel:hover { background: #e2e8f0; }
3212
-
3213
- .pin-edit-save {
3214
- background: #10b981;
3215
- color: #fff;
3216
- }
3217
- .pin-edit-save:hover { background: #059669; }
3438
+ .pin-edit-delete svg { width: 13px; height: 13px; }
3218
3439
 
3219
3440
  /* \u2500\u2500\u2500 Annotation list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
3220
3441