@campfire-interactive/shell-header 0.11.0 → 0.12.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 (2) hide show
  1. package/dist/index.js +54 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -604,6 +604,9 @@ function UserMenu({
604
604
  ] });
605
605
  }
606
606
 
607
+ // src/ShellHeader.tsx
608
+ import { useRef as useRef6, useState as useState7 } from "react";
609
+
607
610
  // src/AboutModal.tsx
608
611
  import { useEffect as useEffect4, useState as useState4 } from "react";
609
612
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -872,7 +875,7 @@ function normalizeRect(x0, y0, x1, y1) {
872
875
  h: Math.abs(y1 - y0)
873
876
  };
874
877
  }
875
- function BugReportModal({ config, onClose }) {
878
+ function BugReportModal({ config, initialScreenshot, onClose }) {
876
879
  const [view, setView] = useState6("form");
877
880
  const [title, setTitle] = useState6("");
878
881
  const [description, setDescription] = useState6("");
@@ -886,6 +889,21 @@ function BugReportModal({ config, onClose }) {
886
889
  const displayCanvasRef = useRef4(null);
887
890
  const dragStartRef = useRef4(null);
888
891
  const [mode, setMode] = useState6("crop");
892
+ const initialLoadedRef = useRef4(false);
893
+ useEffect6(() => {
894
+ if (!initialScreenshot || initialLoadedRef.current) return;
895
+ initialLoadedRef.current = true;
896
+ let cancelled = false;
897
+ void blobToCanvas(initialScreenshot).then((image) => {
898
+ if (cancelled) return;
899
+ originalRef.current = cloneCanvas(image);
900
+ workCanvasRef.current = image;
901
+ setView("editor");
902
+ });
903
+ return () => {
904
+ cancelled = true;
905
+ };
906
+ }, [initialScreenshot]);
889
907
  const closeUnlessBusy = useCallback(() => {
890
908
  if (submitState === "submitting" || capturing) return;
891
909
  if (screenshot) URL.revokeObjectURL(screenshot.previewUrl);
@@ -1075,6 +1093,8 @@ function BugReportModal({ config, onClose }) {
1075
1093
  role: "dialog",
1076
1094
  "aria-modal": "true",
1077
1095
  "aria-label": "Report an issue",
1096
+ onPointerDown: (e) => e.stopPropagation(),
1097
+ onFocus: (e) => e.stopPropagation(),
1078
1098
  children: /* @__PURE__ */ jsxs6("div", { className: `cfi-sh-bug-card${view === "editor" ? " cfi-sh-bug-card-wide" : ""}`, children: [
1079
1099
  /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-header", children: [
1080
1100
  /* @__PURE__ */ jsx6("span", { className: "cfi-sh-bug-title", children: "Report an issue" }),
@@ -1229,9 +1249,10 @@ function cloneCanvas(source) {
1229
1249
  }
1230
1250
 
1231
1251
  // src/useBugReportShortcut.ts
1232
- import { useEffect as useEffect7, useState as useState7 } from "react";
1233
- function useBugReportShortcut(enabled) {
1234
- const [isOpen, setIsOpen] = useState7(false);
1252
+ import { useEffect as useEffect7, useRef as useRef5 } from "react";
1253
+ function useBugReportShortcut(enabled, onShortcut) {
1254
+ const handlerRef = useRef5(onShortcut);
1255
+ handlerRef.current = onShortcut;
1235
1256
  useEffect7(() => {
1236
1257
  if (!enabled) return;
1237
1258
  function handleKeyDown(e) {
@@ -1244,12 +1265,11 @@ function useBugReportShortcut(enabled) {
1244
1265
  if (tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable) return;
1245
1266
  }
1246
1267
  e.preventDefault();
1247
- setIsOpen((open) => !open);
1268
+ handlerRef.current();
1248
1269
  }
1249
1270
  document.addEventListener("keydown", handleKeyDown);
1250
1271
  return () => document.removeEventListener("keydown", handleKeyDown);
1251
1272
  }, [enabled]);
1252
- return [isOpen, setIsOpen];
1253
1273
  }
1254
1274
 
1255
1275
  // src/assets/campfire-wordmark.png
@@ -1287,7 +1307,21 @@ function ShellHeader({
1287
1307
  }) {
1288
1308
  const currentApp = appCatalog.find((a) => a.id === appId);
1289
1309
  const [aboutOpen, setAboutOpen] = useAboutShortcut(about !== void 0);
1290
- const [bugOpen, setBugOpen] = useBugReportShortcut(bugReport !== void 0);
1310
+ const [bugOpen, setBugOpen] = useState7(false);
1311
+ const [bugShot, setBugShot] = useState7(null);
1312
+ const bugCaptureBusy = useRef6(false);
1313
+ useBugReportShortcut(bugReport !== void 0, () => {
1314
+ if (bugOpen) {
1315
+ setBugOpen(false);
1316
+ return;
1317
+ }
1318
+ if (bugCaptureBusy.current) return;
1319
+ bugCaptureBusy.current = true;
1320
+ captureTabScreenshot().then((shot) => setBugShot(shot)).catch(() => setBugShot(null)).finally(() => {
1321
+ bugCaptureBusy.current = false;
1322
+ setBugOpen(true);
1323
+ });
1324
+ });
1291
1325
  const brandStyle = brandWidth ? { width: `${brandWidth}px`, flexShrink: 0, boxSizing: "border-box" } : void 0;
1292
1326
  return /* @__PURE__ */ jsxs7(Fragment4, { children: [
1293
1327
  /* @__PURE__ */ jsxs7("header", { className: "cfi-sh-header", children: [
@@ -1332,17 +1366,27 @@ function ShellHeader({
1332
1366
  ] })
1333
1367
  ] }),
1334
1368
  about && aboutOpen && /* @__PURE__ */ jsx7(AboutModal, { about, onClose: () => setAboutOpen(false) }),
1335
- bugReport && bugOpen && /* @__PURE__ */ jsx7(BugReportModal, { config: bugReport, onClose: () => setBugOpen(false) })
1369
+ bugReport && bugOpen && /* @__PURE__ */ jsx7(
1370
+ BugReportModal,
1371
+ {
1372
+ config: bugReport,
1373
+ initialScreenshot: bugShot,
1374
+ onClose: () => {
1375
+ setBugOpen(false);
1376
+ setBugShot(null);
1377
+ }
1378
+ }
1379
+ )
1336
1380
  ] });
1337
1381
  }
1338
1382
 
1339
1383
  // src/LocaleSwitcher.tsx
1340
- import { useState as useState8, useRef as useRef5, useEffect as useEffect8 } from "react";
1384
+ import { useState as useState8, useRef as useRef7, useEffect as useEffect8 } from "react";
1341
1385
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1342
1386
  function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
1343
1387
  const [open, setOpen] = useState8(false);
1344
1388
  const [updating, setUpdating] = useState8(false);
1345
- const ref = useRef5(null);
1389
+ const ref = useRef7(null);
1346
1390
  useEffect8(() => {
1347
1391
  function handleClickOutside(e) {
1348
1392
  if (ref.current && !ref.current.contains(e.target)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campfire-interactive/shell-header",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "Shared shell header with app switcher for Campfire Suite",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",