@bearmenu/ui 0.8.53 → 0.8.54

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.
@@ -1,5 +1,5 @@
1
1
  import { memo } from "react";
2
- import { MessageSquareQuote, Star } from "lucide-react";
2
+ import { MessageSquareQuote, Star, ThumbsUp } from "lucide-react";
3
3
  import { cn } from "../lib/utils";
4
4
  import { SignatureChip } from "./signature-chip";
5
5
  import type { MenuItemPreview, MenuLinkProps, MenuLinkComponent } from "./menu-types";
@@ -71,6 +71,19 @@ export type MenuItemLabels = {
71
71
  externalRating?: (score: string) => string;
72
72
  };
73
73
 
74
+ /**
75
+ * What the count beside the row counts.
76
+ *
77
+ * - `"mentions"`: every review that named the item, complaints included. Drawn
78
+ * with the quote glyph.
79
+ * - `"praise"`: only the reviews that praised it. Drawn with a thumbs-up.
80
+ *
81
+ * The caller decides, because only the caller knows which number it passed in
82
+ * `item.mentions`. A thumbs-up must never sit on a count that includes
83
+ * complaints, so `"mentions"` is the default.
84
+ */
85
+ export type MenuItemCountKind = "praise" | "mentions";
86
+
74
87
  export type MenuItemProps = {
75
88
  item: MenuItemPreview;
76
89
  labels: MenuItemLabels;
@@ -92,6 +105,12 @@ export type MenuItemProps = {
92
105
  onSignatureEvidence?: () => void;
93
106
  /** Opens the reviews behind the mention count. */
94
107
  onMentions?: () => void;
108
+ /**
109
+ * Whether the count is praise or every mention. Sets the glyph before the
110
+ * numeral: a thumbs-up for `"praise"`, the quote glyph for `"mentions"`.
111
+ * Defaults to `"mentions"`. Keep `labels.mentions` in step with it.
112
+ */
113
+ countKind?: MenuItemCountKind;
95
114
  /**
96
115
  * An outside aggregate score for the item (a wine's Vivino rating, a beer's
97
116
  * Untappd one), shown as a star and the score beside the mention count.
@@ -136,7 +155,9 @@ export type MenuItemProps = {
136
155
  };
137
156
 
138
157
  /**
139
- * The mention count: a filled quote glyph and the numeral, pinned right.
158
+ * The mention count: a glyph and the numeral, pinned right. The glyph is the
159
+ * quote glyph for every mention, or a thumbs-up when the count is praise only
160
+ * (see `MenuItemCountKind`).
140
161
  *
141
162
  * Deliberately NOT a badge — a chip would add a filled shape to a row that has
142
163
  * none, and would read as a status label the venue was given rather than a
@@ -147,18 +168,22 @@ export function MentionSignal({
147
168
  count,
148
169
  onMentions,
149
170
  formatCount = String,
171
+ countKind = "mentions",
150
172
  }: {
151
173
  label: string;
152
174
  count: number;
153
175
  onMentions?: () => void;
154
176
  formatCount?: (value: number) => string;
177
+ countKind?: MenuItemCountKind;
155
178
  }) {
156
179
  /* The glyph and the numeral have to read as ONE object: `gap-0.5` instead of
157
180
  4, and the glyph lighter and a step smaller than the numeral so it reads as
158
- a prefix mark qualifying the value rather than a peer competing with it. */
181
+ a prefix mark qualifying the value rather than a peer competing with it.
182
+ Both glyphs take the same slot, so switching the kind moves nothing. */
183
+ const Glyph = countKind === "praise" ? ThumbsUp : MessageSquareQuote;
159
184
  const content = (
160
185
  <span className="inline-flex items-center gap-0.5">
161
- <MessageSquareQuote className="h-3.5 w-3.5 opacity-60" aria-hidden />
186
+ <Glyph className="h-3.5 w-3.5 opacity-60" aria-hidden />
162
187
  <span className="tabular-nums">{formatCount(count)}</span>
163
188
  </span>
164
189
  );
@@ -233,6 +258,7 @@ export const MenuItem = memo(function MenuItem({
233
258
  signatureTier = "strong",
234
259
  onSignatureEvidence,
235
260
  onMentions,
261
+ countKind = "mentions",
236
262
  externalRating,
237
263
  formatRating = (score) => score.toFixed(1),
238
264
  markGradient,
@@ -455,6 +481,7 @@ export const MenuItem = memo(function MenuItem({
455
481
  count={mentionCount}
456
482
  onMentions={onMentions}
457
483
  formatCount={formatCount}
484
+ countKind={countKind}
458
485
  />
459
486
  )}
460
487
  </div>
@@ -27,7 +27,9 @@ const PopoverContent = React.forwardRef<
27
27
  // than escape.
28
28
  collisionPadding={collisionPadding}
29
29
  className={cn(
30
- "z-50 w-72 rounded-xl border border-border bg-popover p-4 text-popover-foreground shadow-xl outline-none",
30
+ // Drawers and sheets use layer 1000. A body-portalled popover must
31
+ // clear that layer or its visible actions cannot receive a pointer.
32
+ "z-[1010] w-72 rounded-xl border border-border bg-popover p-4 text-popover-foreground shadow-xl outline-none",
31
33
  "max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain",
32
34
  "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
33
35
  className