@the-portland-company/shell 0.39.0 → 0.40.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/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 0.40.0 — 2026-08-03
2
+
3
+ ### Fixed — the DevNotes badge was a second badge definition
4
+
5
+ Reference/UI-Platform "Badge Counters" allows exactly ONE badge definition, and
6
+ `.topbar-widget-slot` in `chrome.css` is supposed to restate it for a launcher
7
+ that brings its own badge markup. It did not: the only rule was
8
+ `.topbar-widget-slot button > span.relative { position: static }`, and DevNotes
9
+ 0.6.x writes that wrapper with an INLINE `position: relative` and **no class**,
10
+ so the selector matched nothing. The badge kept anchoring to the glyph instead
11
+ of the 32px trigger, and its own inline styles (`top:-4 right:-8`, `#dc2626`,
12
+ `font-weight:700`, no `height`) rendered a visibly different bubble — measured
13
+ different on app.politogyvrm.com vs contacts.politogyvrm.com.
14
+
15
+ The slot CSS now (a) matches every direct span child of the launcher, not a
16
+ class, and (b) restates the whole badge definition — 16px circle, `#E63946`
17
+ via `--color-race-red`, 10px / weight 400 / line-height 1, `top:-4px`
18
+ `right:-4px` — with `!important` so inline styles cannot win. `TopBarCountBadge`
19
+ pins `font-weight: 400` and `line-height: 1` explicitly rather than inheriting.
20
+
21
+ ### Fixed — the new-reply toast rendered on top of the notifications panel
22
+
23
+ Both the toast and the panel anchor to the bell trigger, and nothing suppressed
24
+ one while the other was up, so opening Notifications put a message preview over
25
+ the panel's "NOTIFICATIONS" header and first row. `TopBarPopover` gained
26
+ `onOpenChange`; `NotificationsAction` clears the toast when the panel opens,
27
+ refuses to raise a new one while it is open, and does not render it when open.
28
+ One surface per trigger, per Reference/UI-Platform. No z-index was changed.
29
+
1
30
  ## 0.37.1 — 2026-07-27
2
31
 
3
32
  ### Fixed — cross-app navigation kept the user's active organization
@@ -171,7 +171,7 @@ function topBarIconButtonClass(tone = "default") {
171
171
  }
172
172
  function TopBarCountBadge({ count }) {
173
173
  if (!(count > 0)) return null;
174
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-[color:var(--color-race-red)] px-1 text-[10px] text-white", children: count > 99 ? "99+" : count });
174
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-[color:var(--color-race-red)] px-1 text-[10px] font-normal leading-none text-white", children: count > 99 ? "99+" : count });
175
175
  }
176
176
  function TopBarTooltip({
177
177
  title,
@@ -343,10 +343,16 @@ function TopBarPopover({
343
343
  tone,
344
344
  onOpen,
345
345
  openToken,
346
+ onOpenChange,
346
347
  children,
347
348
  panelClassName
348
349
  }) {
349
350
  const [open, setOpen] = react.useState(false);
351
+ const onOpenChangeRef = react.useRef(onOpenChange);
352
+ onOpenChangeRef.current = onOpenChange;
353
+ react.useEffect(() => {
354
+ onOpenChangeRef.current?.(open);
355
+ }, [open]);
350
356
  const rootRef = react.useRef(null);
351
357
  const lastOpenTokenRef = react.useRef(openToken);
352
358
  react.useEffect(() => {
@@ -757,6 +763,7 @@ function NotificationsAction({ orgId }) {
757
763
  const [notif, setNotif] = react.useState(() => readNotifState(orgId));
758
764
  const [toastReply, setToastReply] = react.useState(null);
759
765
  const [openToken, setOpenToken] = react.useState(0);
766
+ const [panelOpen, setPanelOpen] = react.useState(false);
760
767
  react.useEffect(() => {
761
768
  setNotif(readNotifState(orgId));
762
769
  setToastReply(null);
@@ -824,6 +831,7 @@ function NotificationsAction({ orgId }) {
824
831
  [orgId]
825
832
  );
826
833
  const onOpen = react.useCallback(() => {
834
+ setToastReply(null);
827
835
  setNotif((prev) => {
828
836
  const next = { ...prev, lastSeenAt: (/* @__PURE__ */ new Date()).toISOString() };
829
837
  writeNotifState(orgId, next);
@@ -835,7 +843,7 @@ function NotificationsAction({ orgId }) {
835
843
  const imports = payload?.imports ?? [];
836
844
  const quarantined = payload?.quarantined ?? [];
837
845
  react.useEffect(() => {
838
- if (!payload || toastReply) return;
846
+ if (!payload || toastReply || panelOpen) return;
839
847
  const candidate = replies.filter((r) => {
840
848
  if (!r.createdAt) return false;
841
849
  if (notif.lastSeenAt && r.createdAt <= notif.lastSeenAt) return false;
@@ -851,7 +859,7 @@ function NotificationsAction({ orgId }) {
851
859
  writeNotifState(orgId, next);
852
860
  return next;
853
861
  });
854
- }, [payload, replies, toastReply, notif.lastSeenAt, notif.toastedReplyIds, orgId]);
862
+ }, [payload, replies, toastReply, panelOpen, notif.lastSeenAt, notif.toastedReplyIds, orgId]);
855
863
  const onToastActivate = react.useCallback(() => {
856
864
  const href = toastReply?.href;
857
865
  setToastReply(null);
@@ -883,6 +891,7 @@ function NotificationsAction({ orgId }) {
883
891
  badge: loading ? 0 : badgeCount,
884
892
  onOpen,
885
893
  openToken,
894
+ onOpenChange: setPanelOpen,
886
895
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3", children: [
887
896
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Notifications" }),
888
897
  loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 py-1", children: [
@@ -950,7 +959,7 @@ function NotificationsAction({ orgId }) {
950
959
  ] })
951
960
  }
952
961
  ),
953
- toastReply ? /* @__PURE__ */ jsxRuntime.jsx(
962
+ toastReply && !panelOpen ? /* @__PURE__ */ jsxRuntime.jsx(
954
963
  NewReplyToast,
955
964
  {
956
965
  reply: toastReply,