@useclickly/react 1.1.0 → 1.2.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.cjs CHANGED
@@ -499,9 +499,15 @@ async function safeReadText(res) {
499
499
  return "";
500
500
  }
501
501
  }
502
+ var PANEL_W = 284;
503
+ var PANEL_H = 340;
504
+ var PANEL_GAP = 12;
505
+ var VIEWPORT_PAD = 8;
506
+ var TOOLBAR_H = 46;
502
507
  function SettingsPopover({ anchor, width, onClose }) {
503
508
  const ref = react.useRef(null);
504
- const s = useSettings();
509
+ const [view, setView] = react.useState("main");
510
+ const [detailMenuOpen, setDetailMenuOpen] = react.useState(false);
505
511
  react.useEffect(() => {
506
512
  const onDown = (e) => {
507
513
  if (ref.current && e.composedPath().includes(ref.current)) return;
@@ -510,95 +516,162 @@ function SettingsPopover({ anchor, width, onClose }) {
510
516
  window.addEventListener("pointerdown", onDown, true);
511
517
  return () => window.removeEventListener("pointerdown", onDown, true);
512
518
  }, [onClose]);
513
- const PANEL_H = 330;
514
- const top = Math.max(8, anchor.y - PANEL_H - 12);
515
- const left = Math.min(window.innerWidth - 300, Math.max(8, anchor.x + width - 284));
516
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: "clickly-settings", style: { left, top }, children: [
519
+ react.useEffect(() => {
520
+ const onKey = (e) => {
521
+ if (e.key !== "Escape") return;
522
+ if (view !== "main") {
523
+ e.preventDefault();
524
+ setView("main");
525
+ }
526
+ };
527
+ window.addEventListener("keydown", onKey);
528
+ return () => window.removeEventListener("keydown", onKey);
529
+ }, [view]);
530
+ const vw = typeof window !== "undefined" ? window.innerWidth : 1024;
531
+ const vh = typeof window !== "undefined" ? window.innerHeight : 768;
532
+ const spaceAbove = anchor.y - VIEWPORT_PAD;
533
+ const spaceBelow = vh - anchor.y - TOOLBAR_H - VIEWPORT_PAD;
534
+ const placeAbove = spaceAbove >= PANEL_H + PANEL_GAP || spaceAbove >= spaceBelow;
535
+ const top = placeAbove ? Math.max(VIEWPORT_PAD, anchor.y - PANEL_H - PANEL_GAP) : Math.min(vh - PANEL_H - VIEWPORT_PAD, anchor.y + TOOLBAR_H + PANEL_GAP);
536
+ const desiredLeft = anchor.x + width - PANEL_W;
537
+ const left = Math.min(
538
+ vw - PANEL_W - VIEWPORT_PAD,
539
+ Math.max(VIEWPORT_PAD, desiredLeft)
540
+ );
541
+ return /* @__PURE__ */ jsxRuntime.jsx(
542
+ "div",
543
+ {
544
+ ref,
545
+ className: "clickly-settings",
546
+ style: { left, top, width: PANEL_W, height: PANEL_H },
547
+ children: view === "main" ? /* @__PURE__ */ jsxRuntime.jsx(
548
+ MainView,
549
+ {
550
+ onClose,
551
+ onOpenMcp: () => setView("mcp"),
552
+ detailMenuOpen,
553
+ setDetailMenuOpen
554
+ }
555
+ ) : /* @__PURE__ */ jsxRuntime.jsx(McpSubView, { onBack: () => setView("main"), onClose })
556
+ }
557
+ );
558
+ }
559
+ function MainView({
560
+ onClose,
561
+ onOpenMcp,
562
+ detailMenuOpen,
563
+ setDetailMenuOpen
564
+ }) {
565
+ const s = useSettings();
566
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
517
567
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-header", children: [
518
568
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-title", children: "Settings" }),
519
569
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "settings-close", onClick: onClose, "aria-label": "Close settings", children: /* @__PURE__ */ jsxRuntime.jsx(IconClose, {}) })
520
570
  ] }),
521
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-section", children: [
522
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "settings-label", htmlFor: "clickly-detail", children: [
523
- "Output detail",
524
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-hint", children: "How much metadata is captured" })
525
- ] }),
526
- /* @__PURE__ */ jsxRuntime.jsxs(
527
- "select",
528
- {
529
- id: "clickly-detail",
530
- className: "settings-select",
531
- value: s.outputDetail,
532
- onChange: (e) => s.set({ outputDetail: e.target.value }),
533
- children: [
534
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "compact", children: "Compact" }),
535
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "standard", children: "Standard" }),
536
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "detailed", children: "Detailed" }),
537
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "forensic", children: "Forensic" })
538
- ]
539
- }
540
- )
541
- ] }),
542
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "settings-divider" }),
543
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-section", children: [
544
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row", children: [
545
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-label", children: [
546
- "Copy on add",
547
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-hint", children: "Auto-copy markdown when annotating" })
548
- ] }),
549
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "clickly-toggle", children: [
550
- /* @__PURE__ */ jsxRuntime.jsx(
551
- "input",
571
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-scroll", children: [
572
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-compact", children: [
573
+ /* @__PURE__ */ jsxRuntime.jsx(RowLabel, { hint: "How much metadata the markdown output captures.", children: "Output Detail" }),
574
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-inline-select", children: [
575
+ /* @__PURE__ */ jsxRuntime.jsxs(
576
+ "button",
552
577
  {
553
- type: "checkbox",
554
- checked: s.copyOnAdd,
555
- onChange: (e) => s.set({ copyOnAdd: e.target.checked })
578
+ type: "button",
579
+ className: "settings-inline-select-trigger",
580
+ onClick: () => setDetailMenuOpen((v) => !v),
581
+ "aria-haspopup": "menu",
582
+ "aria-expanded": detailMenuOpen,
583
+ children: [
584
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labelForDetail(s.outputDetail) }),
585
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-inline-chev", "aria-hidden": true, children: "\u22EE" })
586
+ ]
556
587
  }
557
588
  ),
558
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "toggle-track" })
559
- ] })
560
- ] }),
561
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row", children: [
562
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-label", children: [
563
- "React components",
564
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-hint", children: "Include component tree in output" })
565
- ] }),
566
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "clickly-toggle", children: [
567
- /* @__PURE__ */ jsxRuntime.jsx(
568
- "input",
589
+ detailMenuOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "settings-inline-menu", role: "menu", children: ["compact", "standard", "detailed", "forensic"].map((v) => /* @__PURE__ */ jsxRuntime.jsx(
590
+ "button",
569
591
  {
570
- type: "checkbox",
571
- checked: s.showReactComponents,
572
- onChange: (e) => s.set({ showReactComponents: e.target.checked })
573
- }
574
- ),
575
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "toggle-track" })
592
+ type: "button",
593
+ role: "menuitemradio",
594
+ "aria-checked": s.outputDetail === v,
595
+ className: `settings-inline-menu-item${s.outputDetail === v ? " is-active" : ""}`,
596
+ onClick: () => {
597
+ s.set({ outputDetail: v });
598
+ setDetailMenuOpen(false);
599
+ },
600
+ children: labelForDetail(v)
601
+ },
602
+ v
603
+ )) }) : null
576
604
  ] })
577
- ] })
578
- ] }),
579
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "settings-divider" }),
580
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "settings-section", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row", children: [
581
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-label", children: [
582
- "Marker color",
583
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-hint", children: "Color used for annotation pins" })
584
605
  ] }),
585
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "settings-color-wrap", "aria-label": "Marker color", children: [
586
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "color-swatch", style: { background: s.markerColor } }),
606
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-compact", children: [
607
+ /* @__PURE__ */ jsxRuntime.jsx(RowLabel, { hint: "Auto-copy markdown to the clipboard every time you submit an annotation.", children: "Copy on Add" }),
587
608
  /* @__PURE__ */ jsxRuntime.jsx(
588
- "input",
609
+ Toggle,
589
610
  {
590
- type: "color",
591
- value: s.markerColor,
592
- onChange: (e) => s.set({ markerColor: e.target.value })
611
+ checked: s.copyOnAdd,
612
+ onChange: (v) => s.set({ copyOnAdd: v })
593
613
  }
594
614
  )
595
- ] })
596
- ] }) }),
597
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "settings-divider" }),
598
- /* @__PURE__ */ jsxRuntime.jsx(McpSection, {})
615
+ ] }),
616
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-compact", children: [
617
+ /* @__PURE__ */ jsxRuntime.jsx(RowLabel, { hint: "Include the React component tree (App \u203A Page \u203A Button) in the output.", children: "React Components" }),
618
+ /* @__PURE__ */ jsxRuntime.jsx(
619
+ Toggle,
620
+ {
621
+ checked: s.showReactComponents,
622
+ onChange: (v) => s.set({ showReactComponents: v })
623
+ }
624
+ )
625
+ ] }),
626
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-compact settings-row-stacked", children: [
627
+ /* @__PURE__ */ jsxRuntime.jsx(RowLabel, { hint: "Color used for the floating annotation pins on the page.", children: "Marker Color" }),
628
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-color-presets", role: "radiogroup", "aria-label": "Marker color", children: [
629
+ MARKER_PRESETS.map((color) => /* @__PURE__ */ jsxRuntime.jsx(
630
+ "button",
631
+ {
632
+ type: "button",
633
+ role: "radio",
634
+ "aria-checked": s.markerColor.toLowerCase() === color.toLowerCase(),
635
+ className: `settings-color-preset${s.markerColor.toLowerCase() === color.toLowerCase() ? " is-active" : ""}`,
636
+ style: { "--preset": color },
637
+ onClick: () => s.set({ markerColor: color }),
638
+ title: color,
639
+ "aria-label": `Use color ${color}`
640
+ },
641
+ color
642
+ )),
643
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "settings-color-preset is-custom", title: "Custom color", children: [
644
+ /* @__PURE__ */ jsxRuntime.jsx(
645
+ "input",
646
+ {
647
+ type: "color",
648
+ value: s.markerColor,
649
+ onChange: (e) => s.set({ markerColor: e.target.value }),
650
+ "aria-label": "Pick a custom marker color"
651
+ }
652
+ ),
653
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-color-custom-glyph", children: "+" })
654
+ ] })
655
+ ] })
656
+ ] }),
657
+ /* @__PURE__ */ jsxRuntime.jsxs(
658
+ "button",
659
+ {
660
+ type: "button",
661
+ className: "settings-disclosure",
662
+ onClick: onOpenMcp,
663
+ "aria-haspopup": "menu",
664
+ children: [
665
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-disclosure-label", children: "Manage MCP & Webhooks" }),
666
+ /* @__PURE__ */ jsxRuntime.jsx(McpStatusDot, {}),
667
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-disclosure-chev", "aria-hidden": true, children: "\u203A" })
668
+ ]
669
+ }
670
+ )
671
+ ] })
599
672
  ] });
600
673
  }
601
- function McpSection() {
674
+ function McpSubView({ onBack, onClose }) {
602
675
  const s = useSettings();
603
676
  const status = useMcpStatus((m) => m.status);
604
677
  const lastError = useMcpStatus((m) => m.lastError);
@@ -611,64 +684,177 @@ function McpSection() {
611
684
  error: { label: "Error", modifier: "is-error" }
612
685
  };
613
686
  const meta = statusMeta[status];
614
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-section", children: [
615
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row", children: [
616
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-label", children: [
617
- "MCP sync",
618
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-hint", children: "Push annotations to a running mcp-server so the agent reads them live" })
619
- ] }),
620
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "clickly-toggle", children: [
621
- /* @__PURE__ */ jsxRuntime.jsx(
622
- "input",
623
- {
624
- type: "checkbox",
625
- checked: s.mcpEnabled,
626
- onChange: (e) => s.set({ mcpEnabled: e.target.checked })
627
- }
628
- ),
629
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "toggle-track" })
630
- ] })
631
- ] }),
632
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row", style: { marginTop: 8 }, children: [
633
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "settings-row-label", style: { flex: "0 0 auto", minWidth: 72 }, children: "Endpoint" }),
634
- /* @__PURE__ */ jsxRuntime.jsx(
635
- "input",
636
- {
637
- type: "text",
638
- className: "settings-input",
639
- value: s.mcpEndpoint,
640
- onChange: (e) => s.set({ mcpEndpoint: e.target.value }),
641
- placeholder: "http://localhost:4747",
642
- disabled: !s.mcpEnabled,
643
- spellCheck: false
644
- }
645
- )
646
- ] }),
647
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `settings-mcp-status ${meta.modifier}`, children: [
648
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-dot", "aria-hidden": true }),
649
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-status-label", children: meta.label }),
650
- status === "connected" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mcp-status-detail", children: [
651
- serverVersion ? `v${serverVersion}` : "",
652
- lastPingAt ? ` \xB7 pinged ${formatRelative(Date.now() - lastPingAt)} ago` : ""
653
- ] }),
654
- status === "error" && lastError ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-status-detail mcp-status-error", children: lastError }) : null
655
- ] }),
656
- status === "connected" && s.mcpSessionId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-mcp-session", children: [
657
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-status-label", style: { opacity: 0.7 }, children: "Session" }),
658
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "mcp-session-id", children: s.mcpSessionId }),
687
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
688
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-header settings-subview-header", children: [
659
689
  /* @__PURE__ */ jsxRuntime.jsx(
660
690
  "button",
661
691
  {
662
692
  type: "button",
663
- className: "mcp-session-reset",
664
- onClick: () => s.set({ mcpSessionId: null }),
665
- title: "Start a fresh session on the next ping",
666
- children: "Reset"
693
+ className: "settings-back",
694
+ onClick: onBack,
695
+ "aria-label": "Back to settings",
696
+ title: "Back (Esc)",
697
+ children: "\u2039"
667
698
  }
668
- )
669
- ] }) : null
699
+ ),
700
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-title", children: "Manage MCP & Webhooks" }),
701
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "settings-close", onClick: onClose, "aria-label": "Close settings", children: /* @__PURE__ */ jsxRuntime.jsx(IconClose, {}) })
702
+ ] }),
703
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-scroll", children: [
704
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-subview-section", children: [
705
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-subview-section-head", children: [
706
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-subview-section-title", children: "MCP Connection" }),
707
+ /* @__PURE__ */ jsxRuntime.jsx(InfoTip, { children: "Lets a running mcp-server bridge annotations to your AI agent. Requires the @useclickly/mcp-server CLI running on your machine." }),
708
+ /* @__PURE__ */ jsxRuntime.jsx(
709
+ Toggle,
710
+ {
711
+ checked: s.mcpEnabled,
712
+ onChange: (v) => s.set({ mcpEnabled: v })
713
+ }
714
+ )
715
+ ] }),
716
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "settings-subview-desc", children: [
717
+ "MCP connection allows agents to receive and act on annotations.",
718
+ " ",
719
+ /* @__PURE__ */ jsxRuntime.jsx(
720
+ "a",
721
+ {
722
+ href: "https://www.useclickly.com/docs/mcp",
723
+ target: "_blank",
724
+ rel: "noreferrer",
725
+ className: "settings-subview-link",
726
+ children: "Learn more"
727
+ }
728
+ )
729
+ ] }),
730
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-subview-field", children: [
731
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "settings-subview-field-label", htmlFor: "clickly-mcp-endpoint", children: "Endpoint" }),
732
+ /* @__PURE__ */ jsxRuntime.jsx(
733
+ "input",
734
+ {
735
+ id: "clickly-mcp-endpoint",
736
+ type: "text",
737
+ className: "settings-input",
738
+ value: s.mcpEndpoint,
739
+ onChange: (e) => s.set({ mcpEndpoint: e.target.value }),
740
+ placeholder: "http://localhost:4747",
741
+ disabled: !s.mcpEnabled,
742
+ spellCheck: false
743
+ }
744
+ )
745
+ ] }),
746
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `settings-mcp-status ${meta.modifier}`, children: [
747
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-dot", "aria-hidden": true }),
748
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-status-label", children: meta.label }),
749
+ status === "connected" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mcp-status-detail", children: [
750
+ serverVersion ? `v${serverVersion}` : "",
751
+ lastPingAt ? ` \xB7 pinged ${formatRelative(Date.now() - lastPingAt)} ago` : ""
752
+ ] }),
753
+ status === "error" && lastError ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-status-detail mcp-status-error", children: lastError }) : null
754
+ ] }),
755
+ status === "connected" && s.mcpSessionId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-mcp-session", children: [
756
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mcp-status-label", style: { opacity: 0.7 }, children: "Session" }),
757
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "mcp-session-id", children: s.mcpSessionId }),
758
+ /* @__PURE__ */ jsxRuntime.jsx(
759
+ "button",
760
+ {
761
+ type: "button",
762
+ className: "mcp-session-reset",
763
+ onClick: () => s.set({ mcpSessionId: null }),
764
+ title: "Start a fresh session on the next ping",
765
+ children: "Reset"
766
+ }
767
+ )
768
+ ] }) : null
769
+ ] }),
770
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-subview-section is-dim", children: [
771
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-subview-section-head", children: [
772
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-subview-section-title", children: "Webhooks" }),
773
+ /* @__PURE__ */ jsxRuntime.jsx(InfoTip, { children: "Forward annotation events to your own server. Not yet available \u2014 open an issue if you want this." }),
774
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-subview-badge", children: "Soon" })
775
+ ] }),
776
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "settings-subview-desc", children: "The webhook URL will receive live annotation changes." }),
777
+ /* @__PURE__ */ jsxRuntime.jsx(
778
+ "textarea",
779
+ {
780
+ className: "settings-input settings-subview-textarea",
781
+ placeholder: "Webhook URL",
782
+ disabled: true,
783
+ rows: 2
784
+ }
785
+ )
786
+ ] })
787
+ ] })
788
+ ] });
789
+ }
790
+ function RowLabel({ children, hint }) {
791
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "settings-row-label-compact", children: [
792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children }),
793
+ hint ? /* @__PURE__ */ jsxRuntime.jsx(InfoTip, { children: hint }) : null
670
794
  ] });
671
795
  }
796
+ function InfoTip({ children }) {
797
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "settings-infotip", tabIndex: 0, "aria-label": "More info", children: [
798
+ "?",
799
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "settings-infotip-bubble", role: "tooltip", children })
800
+ ] });
801
+ }
802
+ function Toggle({
803
+ checked,
804
+ onChange
805
+ }) {
806
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "clickly-toggle", children: [
807
+ /* @__PURE__ */ jsxRuntime.jsx(
808
+ "input",
809
+ {
810
+ type: "checkbox",
811
+ checked,
812
+ onChange: (e) => onChange(e.target.checked)
813
+ }
814
+ ),
815
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "toggle-track" })
816
+ ] });
817
+ }
818
+ function McpStatusDot() {
819
+ const s = useSettings();
820
+ const status = useMcpStatus((m) => m.status);
821
+ if (!s.mcpEnabled) return null;
822
+ return /* @__PURE__ */ jsxRuntime.jsx(
823
+ "span",
824
+ {
825
+ className: `settings-mcp-mini-dot is-${status}`,
826
+ "aria-label": `MCP sync: ${status}`
827
+ }
828
+ );
829
+ }
830
+ function labelForDetail(d) {
831
+ switch (d) {
832
+ case "compact":
833
+ return "Compact";
834
+ case "standard":
835
+ return "Standard";
836
+ case "detailed":
837
+ return "Detailed";
838
+ case "forensic":
839
+ return "Forensic";
840
+ }
841
+ }
842
+ var MARKER_PRESETS = [
843
+ "#6366f1",
844
+ // indigo
845
+ "#0ea5e9",
846
+ // sky
847
+ "#06b6d4",
848
+ // cyan (current default)
849
+ "#10b981",
850
+ // emerald
851
+ "#f59e0b",
852
+ // amber
853
+ "#f97316",
854
+ // orange
855
+ "#ef4444"
856
+ // red
857
+ ];
672
858
  function formatRelative(ms) {
673
859
  if (ms < 1500) return "just now";
674
860
  const s = Math.round(ms / 1e3);
@@ -4427,8 +4613,12 @@ var REACT_UI_CSS = `
4427
4613
  /* \u2500\u2500\u2500 Settings panel (redesigned) \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 */
4428
4614
 
4429
4615
  .clickly-settings {
4616
+ /* Fixed-size frame. Width/height are also set inline by SettingsPopover
4617
+ so the values stay in one place (TS source of truth). The flex
4618
+ column splits: header (fixed) on top, scroll body underneath. */
4430
4619
  position: fixed;
4431
- width: 284px;
4620
+ display: flex;
4621
+ flex-direction: column;
4432
4622
  background: #fff;
4433
4623
  border-radius: 14px;
4434
4624
  box-shadow: 0 16px 48px rgba(2,6,23,0.20), 0 0 0 1px rgba(15,23,42,0.07);
@@ -4440,12 +4630,48 @@ var REACT_UI_CSS = `
4440
4630
  overflow: hidden;
4441
4631
  }
4442
4632
 
4633
+ /* Scrollable body \u2014 wraps everything below the header. Header stays
4634
+ pinned; this region grows to fill the remaining height of the
4635
+ fixed-size .clickly-settings frame and scrolls internally when
4636
+ content overflows.
4637
+
4638
+ The overscroll-behavior:contain rule prevents wheel/touch scroll from
4639
+ bubbling into the host page once you reach the top/bottom of the
4640
+ panel \u2014 without this, scrolling past the end would scroll the user's
4641
+ actual app underneath, which is jarring. */
4642
+ .settings-scroll {
4643
+ flex: 1 1 auto;
4644
+ min-height: 0; /* required for flex children to allow overflow */
4645
+ overflow-y: auto;
4646
+ overscroll-behavior: contain;
4647
+ /* Thin scrollbar in both light + dark themes */
4648
+ scrollbar-width: thin;
4649
+ scrollbar-color: rgba(15,23,42,0.20) transparent;
4650
+ }
4651
+ .settings-scroll::-webkit-scrollbar { width: 6px; }
4652
+ .settings-scroll::-webkit-scrollbar-thumb {
4653
+ background: rgba(15,23,42,0.18);
4654
+ border-radius: 3px;
4655
+ }
4656
+ .settings-scroll::-webkit-scrollbar-thumb:hover { background: rgba(15,23,42,0.32); }
4657
+ :host([data-clickly-theme="dark"]) .settings-scroll {
4658
+ scrollbar-color: rgba(255,255,255,0.18) transparent;
4659
+ }
4660
+ :host([data-clickly-theme="dark"]) .settings-scroll::-webkit-scrollbar-thumb {
4661
+ background: rgba(255,255,255,0.18);
4662
+ }
4663
+ :host([data-clickly-theme="dark"]) .settings-scroll::-webkit-scrollbar-thumb:hover {
4664
+ background: rgba(255,255,255,0.32);
4665
+ }
4666
+
4443
4667
  .settings-header {
4444
4668
  display: flex;
4445
4669
  align-items: center;
4446
4670
  justify-content: space-between;
4447
4671
  padding: 14px 14px 12px;
4448
4672
  border-bottom: 1px solid #f1f5f9;
4673
+ /* Header never shrinks \u2014 body scrolls instead */
4674
+ flex-shrink: 0;
4449
4675
  }
4450
4676
 
4451
4677
  .settings-title {
@@ -4540,6 +4766,415 @@ var REACT_UI_CSS = `
4540
4766
  min-width: 0;
4541
4767
  }
4542
4768
 
4769
+ /* \u2500\u2500\u2500 Dense Agentation-style rows \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
4770
+ * One row per setting, single-line label on the left, control on the
4771
+ * right. Hints move into (?) hover tooltips so the row stays compact.
4772
+ * Used by the refactored SettingsPopover.
4773
+ */
4774
+
4775
+ .settings-row-compact {
4776
+ display: flex;
4777
+ align-items: center;
4778
+ justify-content: space-between;
4779
+ gap: 12px;
4780
+ padding: 10px 14px;
4781
+ border-top: 1px solid #f1f5f9;
4782
+ }
4783
+ .settings-row-compact:first-of-type { border-top: none; }
4784
+ .settings-row-compact.settings-row-stacked {
4785
+ flex-direction: column;
4786
+ align-items: stretch;
4787
+ gap: 8px;
4788
+ }
4789
+
4790
+ .settings-row-label-compact {
4791
+ display: inline-flex;
4792
+ align-items: center;
4793
+ gap: 6px;
4794
+ font-size: 13px;
4795
+ font-weight: 500;
4796
+ color: #1e293b;
4797
+ min-width: 0;
4798
+ }
4799
+
4800
+ /* Info tooltip \u2014 small (?) circle + hover bubble */
4801
+ .settings-infotip {
4802
+ display: inline-grid;
4803
+ place-items: center;
4804
+ width: 14px;
4805
+ height: 14px;
4806
+ border-radius: 50%;
4807
+ background: #e2e8f0;
4808
+ color: #64748b;
4809
+ font: 600 9px/1 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
4810
+ cursor: help;
4811
+ position: relative;
4812
+ flex-shrink: 0;
4813
+ user-select: none;
4814
+ outline: none;
4815
+ }
4816
+ .settings-infotip:hover,
4817
+ .settings-infotip:focus-visible {
4818
+ background: #cbd5e1;
4819
+ color: #1e293b;
4820
+ }
4821
+ .settings-infotip-bubble {
4822
+ position: absolute;
4823
+ bottom: calc(100% + 8px);
4824
+ left: 50%;
4825
+ transform: translateX(-50%);
4826
+ background: rgba(15, 23, 42, 0.98);
4827
+ color: #f1f5f9;
4828
+ font: 400 12px/1.4 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
4829
+ padding: 6px 10px;
4830
+ border-radius: 6px;
4831
+ width: max-content;
4832
+ max-width: 220px;
4833
+ white-space: normal;
4834
+ text-align: left;
4835
+ pointer-events: none;
4836
+ opacity: 0;
4837
+ transition: opacity 100ms ease 150ms;
4838
+ box-shadow: 0 8px 24px rgba(0,0,0,0.30);
4839
+ z-index: 10;
4840
+ }
4841
+ .settings-infotip-bubble::after {
4842
+ content: "";
4843
+ position: absolute;
4844
+ top: 100%;
4845
+ left: 50%;
4846
+ transform: translateX(-50%);
4847
+ border: 4px solid transparent;
4848
+ border-top-color: rgba(15,23,42,0.98);
4849
+ }
4850
+ .settings-infotip:hover .settings-infotip-bubble,
4851
+ .settings-infotip:focus-visible .settings-infotip-bubble { opacity: 1; }
4852
+
4853
+ /* Inline-value selector (Output Detail) */
4854
+ .settings-inline-select { position: relative; }
4855
+ .settings-inline-select-trigger {
4856
+ display: inline-flex;
4857
+ align-items: center;
4858
+ gap: 6px;
4859
+ background: transparent;
4860
+ border: none;
4861
+ font: inherit;
4862
+ font-size: 13px;
4863
+ color: #475569;
4864
+ cursor: pointer;
4865
+ padding: 4px 6px;
4866
+ border-radius: 6px;
4867
+ transition: background 100ms, color 100ms;
4868
+ }
4869
+ .settings-inline-select-trigger:hover { background: #f1f5f9; color: #0f172a; }
4870
+ .settings-inline-chev {
4871
+ font-size: 14px;
4872
+ line-height: 1;
4873
+ color: #94a3b8;
4874
+ transform: rotate(0deg);
4875
+ }
4876
+ .settings-inline-menu {
4877
+ position: absolute;
4878
+ right: 0;
4879
+ top: calc(100% + 6px);
4880
+ min-width: 140px;
4881
+ background: #fff;
4882
+ border-radius: 8px;
4883
+ box-shadow: 0 12px 32px rgba(2,6,23,0.22), 0 0 0 1px rgba(15,23,42,0.06);
4884
+ padding: 4px;
4885
+ z-index: 20;
4886
+ display: flex;
4887
+ flex-direction: column;
4888
+ gap: 1px;
4889
+ animation: clickly-fade-in 80ms ease;
4890
+ }
4891
+ .settings-inline-menu-item {
4892
+ display: flex;
4893
+ align-items: center;
4894
+ justify-content: flex-start;
4895
+ background: transparent;
4896
+ border: none;
4897
+ font: inherit;
4898
+ font-size: 13px;
4899
+ color: #1e293b;
4900
+ cursor: pointer;
4901
+ padding: 7px 10px;
4902
+ border-radius: 6px;
4903
+ text-align: left;
4904
+ transition: background 100ms, color 100ms;
4905
+ }
4906
+ .settings-inline-menu-item:hover { background: #f1f5f9; }
4907
+ .settings-inline-menu-item.is-active {
4908
+ background: rgba(14,165,233,0.10);
4909
+ color: #0284c7;
4910
+ font-weight: 600;
4911
+ }
4912
+
4913
+ /* Marker color preset circles */
4914
+ .settings-color-presets {
4915
+ display: flex;
4916
+ align-items: center;
4917
+ gap: 8px;
4918
+ flex-wrap: wrap;
4919
+ }
4920
+ .settings-color-preset {
4921
+ position: relative;
4922
+ width: 20px;
4923
+ height: 20px;
4924
+ border-radius: 50%;
4925
+ background: var(--preset, #94a3b8);
4926
+ border: none;
4927
+ cursor: pointer;
4928
+ padding: 0;
4929
+ transition: transform 100ms ease;
4930
+ box-shadow:
4931
+ 0 0 0 1.5px rgba(15,23,42,0.06),
4932
+ 0 1px 2px rgba(15,23,42,0.10);
4933
+ }
4934
+ .settings-color-preset:hover { transform: scale(1.08); }
4935
+ .settings-color-preset.is-active {
4936
+ /* Ring around the active preset \u2014 matches Agentation's selected style. */
4937
+ box-shadow:
4938
+ 0 0 0 2px #fff,
4939
+ 0 0 0 4px currentColor,
4940
+ 0 0 0 5px rgba(15,23,42,0.10);
4941
+ color: var(--preset, #0ea5e9);
4942
+ }
4943
+ .settings-color-preset.is-custom {
4944
+ display: inline-grid;
4945
+ place-items: center;
4946
+ background: #f1f5f9;
4947
+ border: 1.5px dashed #cbd5e1;
4948
+ }
4949
+ .settings-color-preset.is-custom input[type="color"] {
4950
+ position: absolute;
4951
+ inset: 0;
4952
+ opacity: 0;
4953
+ cursor: pointer;
4954
+ border: none;
4955
+ background: transparent;
4956
+ padding: 0;
4957
+ }
4958
+ .settings-color-custom-glyph {
4959
+ font: 600 13px/1 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
4960
+ color: #64748b;
4961
+ }
4962
+
4963
+ /* MCP disclosure (collapsible footer row) */
4964
+ .settings-disclosure {
4965
+ display: flex;
4966
+ align-items: center;
4967
+ gap: 8px;
4968
+ width: 100%;
4969
+ background: transparent;
4970
+ border: none;
4971
+ border-top: 1px solid #f1f5f9;
4972
+ padding: 12px 14px;
4973
+ font: inherit;
4974
+ font-size: 13px;
4975
+ font-weight: 500;
4976
+ color: #1e293b;
4977
+ cursor: pointer;
4978
+ text-align: left;
4979
+ transition: background 100ms ease;
4980
+ }
4981
+ .settings-disclosure:hover { background: #f8fafc; }
4982
+ .settings-disclosure-label { flex: 1; }
4983
+ .settings-disclosure-chev {
4984
+ color: #94a3b8;
4985
+ font-size: 16px;
4986
+ line-height: 1;
4987
+ transition: transform 160ms ease;
4988
+ }
4989
+ .settings-disclosure.is-open .settings-disclosure-chev {
4990
+ transform: rotate(90deg);
4991
+ }
4992
+
4993
+ .settings-mcp-mini-dot {
4994
+ width: 7px;
4995
+ height: 7px;
4996
+ border-radius: 50%;
4997
+ background: #94a3b8;
4998
+ flex-shrink: 0;
4999
+ }
5000
+ .settings-mcp-mini-dot.is-connecting {
5001
+ background: #f59e0b;
5002
+ animation: mcp-dot-pulse 1.2s ease-in-out infinite;
5003
+ }
5004
+ .settings-mcp-mini-dot.is-connected { background: #10b981; }
5005
+ .settings-mcp-mini-dot.is-error { background: #ef4444; }
5006
+
5007
+ .settings-mcp-panel {
5008
+ background: rgba(15, 23, 42, 0.02);
5009
+ border-top: 1px solid #f1f5f9;
5010
+ padding: 4px 0 10px;
5011
+ }
5012
+
5013
+ /* \u2500\u2500\u2500 Sub-view (MCP / Webhooks page swap) \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 */
5014
+
5015
+ /* Header gets a back arrow on the left + title centered.
5016
+ Re-uses .settings-header but with a 3-column layout. */
5017
+ .settings-header.settings-subview-header {
5018
+ display: grid;
5019
+ grid-template-columns: 24px 1fr 24px;
5020
+ align-items: center;
5021
+ gap: 8px;
5022
+ }
5023
+ .settings-header.settings-subview-header .settings-title {
5024
+ text-align: center;
5025
+ }
5026
+
5027
+ .settings-back {
5028
+ display: grid;
5029
+ place-items: center;
5030
+ width: 24px;
5031
+ height: 24px;
5032
+ background: transparent;
5033
+ border: none;
5034
+ color: #64748b;
5035
+ font: 600 18px/1 -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
5036
+ cursor: pointer;
5037
+ padding: 0;
5038
+ border-radius: 6px;
5039
+ transition: background 100ms, color 100ms;
5040
+ }
5041
+ .settings-back:hover { background: #f1f5f9; color: #0f172a; }
5042
+
5043
+ .settings-subview-section {
5044
+ padding: 14px 16px 16px;
5045
+ border-top: 1px solid #f1f5f9;
5046
+ }
5047
+ .settings-subview-section:first-of-type { border-top: none; }
5048
+ .settings-subview-section.is-dim { opacity: 0.65; }
5049
+
5050
+ .settings-subview-section-head {
5051
+ display: flex;
5052
+ align-items: center;
5053
+ gap: 6px;
5054
+ margin-bottom: 6px;
5055
+ }
5056
+ .settings-subview-section-title {
5057
+ font-size: 14px;
5058
+ font-weight: 600;
5059
+ color: #0f172a;
5060
+ flex: 1;
5061
+ }
5062
+ .settings-subview-section-head .clickly-toggle { margin-left: auto; }
5063
+
5064
+ .settings-subview-desc {
5065
+ margin: 0 0 12px;
5066
+ font-size: 12.5px;
5067
+ line-height: 1.5;
5068
+ color: #64748b;
5069
+ }
5070
+
5071
+ .settings-subview-link {
5072
+ color: #0ea5e9;
5073
+ text-decoration: none;
5074
+ font-weight: 500;
5075
+ }
5076
+ .settings-subview-link:hover {
5077
+ color: #0284c7;
5078
+ text-decoration: underline;
5079
+ }
5080
+
5081
+ .settings-subview-field {
5082
+ display: flex;
5083
+ flex-direction: column;
5084
+ gap: 6px;
5085
+ margin-bottom: 10px;
5086
+ }
5087
+ .settings-subview-field-label {
5088
+ font-size: 12px;
5089
+ font-weight: 600;
5090
+ color: #475569;
5091
+ text-transform: uppercase;
5092
+ letter-spacing: 0.04em;
5093
+ }
5094
+
5095
+ .settings-subview-textarea {
5096
+ resize: none;
5097
+ min-height: 56px;
5098
+ font-family: ui-monospace, "SF Mono", Menlo, monospace;
5099
+ font-size: 12px;
5100
+ }
5101
+
5102
+ .settings-subview-badge {
5103
+ margin-left: auto;
5104
+ font-size: 10px;
5105
+ font-weight: 600;
5106
+ text-transform: uppercase;
5107
+ letter-spacing: 0.05em;
5108
+ padding: 2px 6px;
5109
+ border-radius: 4px;
5110
+ background: #fef3c7;
5111
+ color: #b45309;
5112
+ }
5113
+
5114
+ :host([data-clickly-theme="dark"]) .settings-back { color: #94a3b8; }
5115
+ :host([data-clickly-theme="dark"]) .settings-back:hover {
5116
+ background: rgba(255,255,255,0.06);
5117
+ color: #f8fafc;
5118
+ }
5119
+ :host([data-clickly-theme="dark"]) .settings-subview-section {
5120
+ border-top-color: rgba(255,255,255,0.06);
5121
+ }
5122
+ :host([data-clickly-theme="dark"]) .settings-subview-section-title { color: #f1f5f9; }
5123
+ :host([data-clickly-theme="dark"]) .settings-subview-desc { color: #94a3b8; }
5124
+ :host([data-clickly-theme="dark"]) .settings-subview-field-label { color: #94a3b8; }
5125
+ :host([data-clickly-theme="dark"]) .settings-subview-link { color: #38bdf8; }
5126
+ :host([data-clickly-theme="dark"]) .settings-subview-link:hover { color: #7dd3fc; }
5127
+ :host([data-clickly-theme="dark"]) .settings-subview-badge {
5128
+ background: rgba(245, 158, 11, 0.18);
5129
+ color: #fbbf24;
5130
+ }
5131
+
5132
+ /* Dark-mode overrides for the new compact rows */
5133
+ :host([data-clickly-theme="dark"]) .settings-row-compact { border-top-color: rgba(255,255,255,0.06); }
5134
+ :host([data-clickly-theme="dark"]) .settings-row-label-compact { color: #e2e8f0; }
5135
+ :host([data-clickly-theme="dark"]) .settings-infotip { background: rgba(255,255,255,0.10); color: #94a3b8; }
5136
+ :host([data-clickly-theme="dark"]) .settings-infotip:hover { background: rgba(255,255,255,0.18); color: #f8fafc; }
5137
+ :host([data-clickly-theme="dark"]) .settings-inline-select-trigger { color: #cbd5e1; }
5138
+ :host([data-clickly-theme="dark"]) .settings-inline-select-trigger:hover {
5139
+ background: rgba(255,255,255,0.06);
5140
+ color: #f8fafc;
5141
+ }
5142
+ :host([data-clickly-theme="dark"]) .settings-inline-menu {
5143
+ background: #1e293b;
5144
+ box-shadow: 0 12px 32px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.08);
5145
+ }
5146
+ :host([data-clickly-theme="dark"]) .settings-inline-menu-item { color: #e2e8f0; }
5147
+ :host([data-clickly-theme="dark"]) .settings-inline-menu-item:hover { background: rgba(255,255,255,0.06); }
5148
+ :host([data-clickly-theme="dark"]) .settings-inline-menu-item.is-active {
5149
+ background: rgba(14,165,233,0.20);
5150
+ color: #7dd3fc;
5151
+ }
5152
+ :host([data-clickly-theme="dark"]) .settings-color-preset {
5153
+ box-shadow:
5154
+ 0 0 0 1.5px rgba(255,255,255,0.10),
5155
+ 0 1px 2px rgba(0,0,0,0.40);
5156
+ }
5157
+ :host([data-clickly-theme="dark"]) .settings-color-preset.is-active {
5158
+ box-shadow:
5159
+ 0 0 0 2px #0f172a,
5160
+ 0 0 0 4px currentColor,
5161
+ 0 0 0 5px rgba(255,255,255,0.10);
5162
+ }
5163
+ :host([data-clickly-theme="dark"]) .settings-color-preset.is-custom {
5164
+ background: rgba(255,255,255,0.05);
5165
+ border-color: rgba(255,255,255,0.20);
5166
+ }
5167
+ :host([data-clickly-theme="dark"]) .settings-color-custom-glyph { color: #cbd5e1; }
5168
+ :host([data-clickly-theme="dark"]) .settings-disclosure {
5169
+ color: #e2e8f0;
5170
+ border-top-color: rgba(255,255,255,0.06);
5171
+ }
5172
+ :host([data-clickly-theme="dark"]) .settings-disclosure:hover { background: rgba(255,255,255,0.04); }
5173
+ :host([data-clickly-theme="dark"]) .settings-mcp-panel {
5174
+ background: rgba(255,255,255,0.02);
5175
+ border-top-color: rgba(255,255,255,0.06);
5176
+ }
5177
+
4543
5178
  /* Toggle switch */
4544
5179
  .clickly-toggle {
4545
5180
  position: relative;