@planningcenter/topbar 12.4.0 → 12.4.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.
@@ -34437,7 +34437,8 @@ true;
34437
34437
  onClick: () => onClick(),
34438
34438
  type: "button"
34439
34439
  }, /*#__PURE__*/React.createElement(SparkleIcon, {
34440
- className: styles.sparkle
34440
+ className: styles.sparkle,
34441
+ fill: "currentColor"
34441
34442
  }), /*#__PURE__*/React.createElement("span", {
34442
34443
  className: styles.label
34443
34444
  }, text));
@@ -34626,6 +34627,9 @@ true;
34626
34627
  // Contact support) and picobot's own NEW_ROUTE_RENDERED reports—so it
34627
34628
  // always reflects the live conversation. See buildPicobotSrc.
34628
34629
  const [loadedPath, setLoadedPath] = React.useState(iframePath || "");
34630
+ // Hidden until picobot paints so its blank first frame doesn't flash
34631
+ // white against the drawer in dark mode.
34632
+ const [isReady, setIsReady] = React.useState(false);
34629
34633
  const hasReportedErrorRef = React.useRef(false);
34630
34634
  const loadTimeoutRef = React.useRef();
34631
34635
  const reportLoadError = React.useCallback(() => {
@@ -34653,7 +34657,10 @@ true;
34653
34657
  setLoadedPath(reportedPath);
34654
34658
  onIframeChangePath(reportedPath);
34655
34659
  }
34656
- if (((_c = e.data) === null || _c === void 0 ? void 0 : _c.type) === "READY") clearTimeout(loadTimeoutRef.current);
34660
+ if (((_c = e.data) === null || _c === void 0 ? void 0 : _c.type) === "READY") {
34661
+ clearTimeout(loadTimeoutRef.current);
34662
+ setIsReady(true);
34663
+ }
34657
34664
  if (onMessage) onMessage(e.data);
34658
34665
  }
34659
34666
  window.addEventListener("message", handleGuestMessage);
@@ -34663,12 +34670,15 @@ true;
34663
34670
  setLoadedPath(iframePath || "");
34664
34671
  }, [iframePath]);
34665
34672
  // A one-way channel for sending messages to picobot. Topbar just
34666
- // forwards the envelope to the iframe and holds no message semantics of
34667
- // its own—the consumer decides what to send and when.
34673
+ // forwards the envelope to the iframe—the consumer decides what to send
34674
+ // and when. The one exception is PANE_VISIBLE: Safari ignores focus()
34675
+ // from inside a cross-origin iframe, so the host has to focus the iframe
34676
+ // before picobot can focus its composer.
34668
34677
  React.useImperativeHandle(ref, () => ({
34669
34678
  postMessage(message) {
34670
- var _a, _b;
34671
- (_b = (_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.contentWindow) === null || _b === void 0 ? void 0 : _b.postMessage(message, picobotOrigin);
34679
+ var _a, _b, _c;
34680
+ if (message.type === "PANE_VISIBLE") (_a = iframeRef.current) === null || _a === void 0 ? void 0 : _a.focus();
34681
+ (_c = (_b = iframeRef.current) === null || _b === void 0 ? void 0 : _b.contentWindow) === null || _c === void 0 ? void 0 : _c.postMessage(message, picobotOrigin);
34672
34682
  }
34673
34683
  }), []);
34674
34684
  const iframeSrc = buildPicobotSrc(picobotOrigin, loadedPath, {
@@ -34682,6 +34692,7 @@ true;
34682
34692
  border: 0,
34683
34693
  flex: 1,
34684
34694
  height: "100%",
34695
+ visibility: isReady ? undefined : "hidden",
34685
34696
  width: "100%"
34686
34697
  },
34687
34698
  title: "Picobot"
@@ -35410,6 +35421,7 @@ true;
35410
35421
  closeDrawer,
35411
35422
  currentPath,
35412
35423
  env,
35424
+ isOpen,
35413
35425
  onChangePath,
35414
35426
  openTool,
35415
35427
  pending
@@ -35454,6 +35466,17 @@ true;
35454
35466
  }
35455
35467
  clearPending();
35456
35468
  }, [pending, isPicobotReady, clearPending]);
35469
+ // The drawer keeps the iframe mounted while it's closed, so picobot's
35470
+ // autofocus is spent by the time the panel reopens. READY gates the signal
35471
+ // because picobot has no listener before it.
35472
+ React.useEffect(function tellPicobotThePanelIsVisible() {
35473
+ var _a;
35474
+ if (isOpen && isPicobotReady) {
35475
+ (_a = picobotRef.current) === null || _a === void 0 ? void 0 : _a.postMessage({
35476
+ type: "PANE_VISIBLE"
35477
+ });
35478
+ }
35479
+ }, [isOpen, isPicobotReady]);
35457
35480
  const [iframeErrored, setIframeErrored] = React.useState(false);
35458
35481
  const [mountKey, setMountKey] = React.useState(0);
35459
35482
  const handleRetry = React.useCallback(() => {
@@ -35970,6 +35993,11 @@ true;
35970
35993
  };
35971
35994
 
35972
35995
  const DURATION = 100;
35996
+ const TOOLBAR_DRAWER_CHANGE_EVENT = "topbar:toolbar-drawer-change";
35997
+ const CLOSED_TOOLBAR_DRAWER = {
35998
+ open: false,
35999
+ tool: null
36000
+ };
35973
36001
  // Exempt paths match regardless of query, so `email?conversationId=…` is
35974
36002
  // exempt along with `email`.
35975
36003
  function isToolPathExemptFromStorage(toolName, path) {
@@ -36083,6 +36111,27 @@ true;
36083
36111
  delete window.openHelpdesk; /* TODO: Remove when products have migrated to window.topbar.openHelpdesk */
36084
36112
  };
36085
36113
  }, [Profile, openHelpdeskAtRoot]);
36114
+ const toolbarDrawerTool = open && currentContent ? currentContent.name.toLowerCase() : null;
36115
+ const lastToolbarDrawer = React.useRef(CLOSED_TOOLBAR_DRAWER);
36116
+ React.useEffect(() => {
36117
+ const toolbarDrawer = {
36118
+ open,
36119
+ tool: toolbarDrawerTool
36120
+ };
36121
+ window.topbar = window.topbar || {};
36122
+ window.topbar.toolbarDrawer = toolbarDrawer;
36123
+ const last = lastToolbarDrawer.current;
36124
+ if (last.open !== toolbarDrawer.open || last.tool !== toolbarDrawer.tool) {
36125
+ lastToolbarDrawer.current = toolbarDrawer;
36126
+ window.dispatchEvent(new CustomEvent(TOOLBAR_DRAWER_CHANGE_EVENT, {
36127
+ detail: toolbarDrawer
36128
+ }));
36129
+ }
36130
+ return () => {
36131
+ var _a;
36132
+ (_a = window.topbar) === null || _a === void 0 ? true : delete _a.toolbarDrawer;
36133
+ };
36134
+ }, [open, toolbarDrawerTool]);
36086
36135
  const loginSettingsUrl = getLoginProfilePath({
36087
36136
  appName: appName.replace(/[\s-]/, ""),
36088
36137
  env: env,