@bearmenu/ui 0.8.52 → 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.
Files changed (44) hide show
  1. package/dist/{chunk-4WW3HPIW.js → chunk-6Z6MBILC.js} +8 -4
  2. package/dist/chunk-GIJGVFGC.js +177 -0
  3. package/dist/chunk-RKNPPYRU.js +86 -0
  4. package/dist/{chunk-2ADCZXZJ.js → chunk-RXXD3UYP.js} +3 -1
  5. package/dist/components/alert.d.ts +2 -2
  6. package/dist/components/badge.d.ts +1 -1
  7. package/dist/components/button.d.ts +2 -2
  8. package/dist/components/combobox.js +1 -1
  9. package/dist/components/event-detail-panel.d.ts +17 -6
  10. package/dist/components/event-detail-panel.js +58 -8
  11. package/dist/components/facet-group.d.ts +9 -2
  12. package/dist/components/facet-group.js +108 -10
  13. package/dist/components/filter-option-chip.d.ts +15 -0
  14. package/dist/components/filter-option-chip.js +3 -0
  15. package/dist/components/filter-option-group.d.ts +37 -0
  16. package/dist/components/filter-option-group.js +10 -0
  17. package/dist/components/filter-panel-footer.d.ts +15 -0
  18. package/dist/components/filter-panel-footer.js +63 -0
  19. package/dist/components/menu-item.d.ts +24 -3
  20. package/dist/components/menu-item.js +1 -1
  21. package/dist/components/multi-select-combobox.js +1 -1
  22. package/dist/components/place-card.js +1 -1
  23. package/dist/components/popover.js +1 -1
  24. package/dist/components/searchable-select.js +1 -1
  25. package/dist/components/spinner.d.ts +2 -2
  26. package/dist/components/tag.d.ts +2 -2
  27. package/dist/components/text.d.ts +1 -1
  28. package/dist/components/toggle.d.ts +1 -1
  29. package/dist/components/top-ranking-entry.js +1 -1
  30. package/package.json +11 -8
  31. package/src/components/event-detail-panel.stories.tsx +16 -0
  32. package/src/components/event-detail-panel.test.tsx +36 -0
  33. package/src/components/event-detail-panel.tsx +86 -14
  34. package/src/components/facet-group.tsx +153 -54
  35. package/src/components/filter-option-chip.test.tsx +50 -0
  36. package/src/components/filter-option-chip.tsx +81 -0
  37. package/src/components/filter-option-group.stories.tsx +250 -0
  38. package/src/components/filter-option-group.test.tsx +100 -0
  39. package/src/components/filter-option-group.tsx +231 -0
  40. package/src/components/filter-panel-footer.tsx +63 -0
  41. package/src/components/menu-item.stories.tsx +82 -0
  42. package/src/components/menu-item.test.tsx +55 -1
  43. package/src/components/menu-item.tsx +31 -4
  44. package/src/components/popover.tsx +3 -1
@@ -2,7 +2,7 @@ import { SignatureChip } from './chunk-6PQINSAA.js';
2
2
  import { cn } from './chunk-FEK5XGZW.js';
3
3
  import { __objRest, __spreadValues } from './chunk-MMUBH76A.js';
4
4
  import { memo } from 'react';
5
- import { Star, MessageSquareQuote } from 'lucide-react';
5
+ import { Star, ThumbsUp, MessageSquareQuote } from 'lucide-react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
7
 
8
8
  function DefaultLink(_a) {
@@ -13,10 +13,12 @@ function MentionSignal({
13
13
  label,
14
14
  count,
15
15
  onMentions,
16
- formatCount = String
16
+ formatCount = String,
17
+ countKind = "mentions"
17
18
  }) {
19
+ const Glyph = countKind === "praise" ? ThumbsUp : MessageSquareQuote;
18
20
  const content = /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-0.5", children: [
19
- /* @__PURE__ */ jsx(MessageSquareQuote, { className: "h-3.5 w-3.5 opacity-60", "aria-hidden": true }),
21
+ /* @__PURE__ */ jsx(Glyph, { className: "h-3.5 w-3.5 opacity-60", "aria-hidden": true }),
20
22
  /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: formatCount(count) })
21
23
  ] });
22
24
  const shared = cn(
@@ -75,6 +77,7 @@ var MenuItem = memo(function MenuItem2({
75
77
  signatureTier = "strong",
76
78
  onSignatureEvidence,
77
79
  onMentions,
80
+ countKind = "mentions",
78
81
  externalRating,
79
82
  formatRating = (score) => score.toFixed(1),
80
83
  markGradient,
@@ -225,7 +228,8 @@ var MenuItem = memo(function MenuItem2({
225
228
  label: labels.mentions(mentionCount),
226
229
  count: mentionCount,
227
230
  onMentions,
228
- formatCount
231
+ formatCount,
232
+ countKind
229
233
  }
230
234
  )
231
235
  ] })
@@ -0,0 +1,177 @@
1
+ import { FilterOptionChip } from './chunk-RKNPPYRU.js';
2
+ import { Separator } from './chunk-NWZGSLPU.js';
3
+ import { Button } from './chunk-GHKTVHQG.js';
4
+ import { Text } from './chunk-ZLMRVBD7.js';
5
+ import { Badge } from './chunk-RYPPN2GZ.js';
6
+ import { cn } from './chunk-FEK5XGZW.js';
7
+ import { useId, useState } from 'react';
8
+ import { ChevronDown } from 'lucide-react';
9
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
10
+
11
+ function FilterOptionGroup({
12
+ title,
13
+ options,
14
+ value,
15
+ onValueChange,
16
+ selection = "multiple",
17
+ name,
18
+ defaultOpen = false,
19
+ collapsible = true,
20
+ visibleLimit = 6,
21
+ showAllLabel,
22
+ showLessLabel,
23
+ children,
24
+ footer,
25
+ clearLabel,
26
+ onClear,
27
+ summaryValues = value,
28
+ className,
29
+ divider = true,
30
+ disabled
31
+ }) {
32
+ const id = useId();
33
+ const [isOpen, setOpen] = useState(defaultOpen);
34
+ const open = !collapsible || isOpen;
35
+ const [expanded, setExpanded] = useState([]);
36
+ const selected = options.filter(
37
+ (option) => summaryValues.includes(option.value)
38
+ );
39
+ const sections = [];
40
+ for (const option of options) {
41
+ const last = sections[sections.length - 1];
42
+ if (!last || last.label !== option.section)
43
+ sections.push({ label: option.section, options: [option] });
44
+ else last.options.push(option);
45
+ }
46
+ const heading = /* @__PURE__ */ jsxs(Fragment, { children: [
47
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
48
+ /* @__PURE__ */ jsx(
49
+ Text,
50
+ {
51
+ as: "span",
52
+ id: `${id}-title`,
53
+ className: "block",
54
+ variant: "body-sm",
55
+ weight: "semibold",
56
+ children: title
57
+ }
58
+ ),
59
+ !open && selected.length > 0 && /* @__PURE__ */ jsx(
60
+ Text,
61
+ {
62
+ as: "span",
63
+ variant: "caption",
64
+ color: "muted",
65
+ className: "mt-1 block leading-relaxed [overflow-wrap:anywhere]",
66
+ children: selected.map((option) => option.label).join(" \xB7 ")
67
+ }
68
+ )
69
+ ] }),
70
+ selected.length > 0 && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "tabular-nums", children: selected.length }),
71
+ collapsible && /* @__PURE__ */ jsx(
72
+ ChevronDown,
73
+ {
74
+ "aria-hidden": true,
75
+ className: cn(
76
+ "size-4 shrink-0 text-muted-foreground transition-transform motion-reduce:transition-none",
77
+ open && "rotate-180"
78
+ )
79
+ }
80
+ )
81
+ ] });
82
+ return /* @__PURE__ */ jsxs("section", { className: cn("min-w-0", className), children: [
83
+ /* @__PURE__ */ jsxs("div", { className: "py-2", children: [
84
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
85
+ collapsible ? /* @__PURE__ */ jsx(
86
+ "button",
87
+ {
88
+ type: "button",
89
+ onClick: () => setOpen((previous) => !previous),
90
+ "aria-expanded": open,
91
+ "aria-controls": id,
92
+ className: "flex min-h-11 min-w-0 flex-1 items-center gap-3 rounded-lg py-2 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
93
+ children: heading
94
+ }
95
+ ) : /* @__PURE__ */ jsx("div", { className: "flex min-h-11 min-w-0 flex-1 items-center gap-3 py-2", children: heading }),
96
+ onClear && clearLabel && summaryValues.length > 0 && /* @__PURE__ */ jsx(
97
+ Button,
98
+ {
99
+ type: "button",
100
+ variant: "ghost",
101
+ className: "min-h-11 shrink-0 px-2 text-xs",
102
+ onClick: onClear,
103
+ children: clearLabel
104
+ }
105
+ )
106
+ ] }),
107
+ /* @__PURE__ */ jsxs("div", { id, hidden: !open, children: [
108
+ children,
109
+ sections.map((section, index) => {
110
+ var _a;
111
+ const sectionId = `${id}-section-${index}`;
112
+ const key = (_a = section.label) != null ? _a : "";
113
+ const isExpanded = expanded.includes(key);
114
+ const limit = showAllLabel ? visibleLimit : Infinity;
115
+ const visible = isExpanded ? section.options : section.options.filter(
116
+ (option, i) => i < limit || value.includes(option.value)
117
+ );
118
+ return /* @__PURE__ */ jsxs("div", { children: [
119
+ section.label && /* @__PURE__ */ jsx(
120
+ Text,
121
+ {
122
+ as: "h4",
123
+ id: sectionId,
124
+ variant: "caption",
125
+ weight: "semibold",
126
+ color: "muted",
127
+ className: "mt-3 mb-1",
128
+ children: section.label
129
+ }
130
+ ),
131
+ /* @__PURE__ */ jsx(
132
+ "fieldset",
133
+ {
134
+ "aria-labelledby": `${id}-title${section.label ? ` ${sectionId}` : ""}`,
135
+ disabled,
136
+ className: "m-0 flex min-w-0 flex-wrap gap-2 border-0 px-0 pt-2 pb-3",
137
+ children: visible.map((option) => /* @__PURE__ */ jsx(
138
+ FilterOptionChip,
139
+ {
140
+ label: option.label,
141
+ count: option.count,
142
+ icon: option.icon,
143
+ type: selection === "single" ? "radio" : "checkbox",
144
+ name: selection === "single" ? name != null ? name : id : void 0,
145
+ value: option.value,
146
+ checked: value.includes(option.value),
147
+ onChange: (event) => onValueChange(
148
+ selection === "single" ? [option.value] : event.target.checked ? [...value, option.value] : value.filter((item) => item !== option.value)
149
+ )
150
+ },
151
+ option.value
152
+ ))
153
+ }
154
+ ),
155
+ section.options.length > limit && /* @__PURE__ */ jsx(
156
+ Button,
157
+ {
158
+ type: "button",
159
+ variant: "link",
160
+ "aria-expanded": isExpanded,
161
+ onClick: () => setExpanded(
162
+ (previous) => isExpanded ? previous.filter((item) => item !== key) : [...previous, key]
163
+ ),
164
+ className: "mb-1 min-h-11 px-0",
165
+ children: isExpanded ? showLessLabel : typeof showAllLabel === "function" ? showAllLabel(section.options.length) : showAllLabel
166
+ }
167
+ )
168
+ ] }, key);
169
+ }),
170
+ footer
171
+ ] })
172
+ ] }),
173
+ divider && /* @__PURE__ */ jsx(Separator, {})
174
+ ] });
175
+ }
176
+
177
+ export { FilterOptionGroup };
@@ -0,0 +1,86 @@
1
+ import { cn } from './chunk-FEK5XGZW.js';
2
+ import { __objRest, __spreadProps, __spreadValues } from './chunk-MMUBH76A.js';
3
+ import { useId } from 'react';
4
+ import { Check } from 'lucide-react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function FilterOptionChip(_a) {
8
+ var _b = _a, {
9
+ label,
10
+ type = "checkbox",
11
+ count,
12
+ icon,
13
+ className,
14
+ id,
15
+ disabled
16
+ } = _b, input = __objRest(_b, [
17
+ "label",
18
+ "type",
19
+ "count",
20
+ "icon",
21
+ "className",
22
+ "id",
23
+ "disabled"
24
+ ]);
25
+ var _a2;
26
+ const generatedId = useId();
27
+ const inputId = id != null ? id : generatedId;
28
+ return /* @__PURE__ */ jsxs(
29
+ "label",
30
+ {
31
+ htmlFor: inputId,
32
+ className: cn(
33
+ "relative inline-flex max-w-full min-w-0",
34
+ disabled && "cursor-not-allowed opacity-50",
35
+ className
36
+ ),
37
+ children: [
38
+ /* @__PURE__ */ jsx(
39
+ "input",
40
+ __spreadProps(__spreadValues({}, input), {
41
+ id: inputId,
42
+ type,
43
+ disabled,
44
+ "aria-label": (_a2 = input["aria-label"]) != null ? _a2 : label,
45
+ className: "peer sr-only"
46
+ })
47
+ ),
48
+ /* @__PURE__ */ jsxs(
49
+ "span",
50
+ {
51
+ className: cn(
52
+ "flex min-h-11 min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-2xl border border-border bg-background px-3 py-2 text-sm text-foreground",
53
+ "transition-colors hover:bg-muted motion-reduce:transition-none",
54
+ "peer-checked:border-primary peer-checked:bg-primary/10 peer-checked:shadow-[inset_0_0_0_1px_var(--primary)] peer-checked:text-primary",
55
+ "peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-ring",
56
+ "peer-disabled:pointer-events-none peer-disabled:cursor-not-allowed",
57
+ "[&_.filter-check]:hidden peer-checked:[&_.filter-check]:block peer-checked:[&_.filter-icon]:hidden"
58
+ ),
59
+ children: [
60
+ /* @__PURE__ */ jsx(
61
+ Check,
62
+ {
63
+ "aria-hidden": true,
64
+ className: "filter-check size-4 shrink-0",
65
+ strokeWidth: 2.5
66
+ }
67
+ ),
68
+ icon && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "filter-icon shrink-0 [&>svg]:size-4", children: icon }),
69
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 [overflow-wrap:anywhere]", children: label }),
70
+ count != null && /* @__PURE__ */ jsx(
71
+ "span",
72
+ {
73
+ "aria-hidden": true,
74
+ className: "shrink-0 text-xs tabular-nums text-muted-foreground",
75
+ children: count
76
+ }
77
+ )
78
+ ]
79
+ }
80
+ )
81
+ ]
82
+ }
83
+ );
84
+ }
85
+
86
+ export { FilterOptionChip };
@@ -19,7 +19,9 @@ var PopoverContent = React.forwardRef((_a, ref) => {
19
19
  sideOffset,
20
20
  collisionPadding,
21
21
  className: cn(
22
- "z-50 w-72 rounded-xl border border-border bg-popover p-4 text-popover-foreground shadow-xl outline-none",
22
+ // Drawers and sheets use layer 1000. A body-portalled popover must
23
+ // clear that layer or its visible actions cannot receive a pointer.
24
+ "z-[1010] w-72 rounded-xl border border-border bg-popover p-4 text-popover-foreground shadow-xl outline-none",
23
25
  "max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain",
24
26
  "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",
25
27
  className
@@ -3,10 +3,10 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const alertVariants: (props?: ({
6
- variant?: "default" | "success" | "warning" | "destructive" | null | undefined;
6
+ variant?: "success" | "warning" | "default" | "destructive" | null | undefined;
7
7
  } & class_variance_authority_types.ClassProp) | undefined) => string;
8
8
  declare const Alert: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & VariantProps<(props?: ({
9
- variant?: "default" | "success" | "warning" | "destructive" | null | undefined;
9
+ variant?: "success" | "warning" | "default" | "destructive" | null | undefined;
10
10
  } & class_variance_authority_types.ClassProp) | undefined) => string> & React.RefAttributes<HTMLDivElement>>;
11
11
  declare const AlertTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
12
12
  declare const AlertDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
@@ -4,7 +4,7 @@ import * as React from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "secondary" | "default" | "success" | "warning" | "destructive" | "outline" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | "completed" | "assignee" | "softSuccess" | "softWarning" | "softDestructive" | "softNeutral" | null | undefined;
7
+ variant?: "secondary" | "success" | "warning" | "default" | "destructive" | "outline" | "glass" | "overlay" | "brown" | "code" | "onPrimary" | "confirmed" | "pending" | "completed" | "assignee" | "softSuccess" | "softWarning" | "softDestructive" | "softNeutral" | null | undefined;
8
8
  size?: "status" | "chip" | null | undefined;
9
9
  live?: boolean | null | undefined;
10
10
  } & class_variance_authority_types.ClassProp) | undefined) => string;
@@ -3,8 +3,8 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const buttonVariants: (props?: ({
6
- variant?: "secondary" | "default" | "link" | "warning" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
7
- size?: "default" | "icon" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
6
+ variant?: "secondary" | "link" | "warning" | "default" | "destructive" | "outline" | "ghost" | "glass" | "overlay" | "ink" | "brown" | "cta" | null | undefined;
7
+ size?: "icon" | "default" | "cta" | "xs" | "sm" | "lg" | "pill" | "cta-sm" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
8
8
  fullWidth?: boolean | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
@@ -1,4 +1,4 @@
1
- import { Popover, PopoverTrigger, PopoverContent } from '../chunk-2ADCZXZJ.js';
1
+ import { Popover, PopoverTrigger, PopoverContent } from '../chunk-RXXD3UYP.js';
2
2
  import { Command, CommandInput, CommandList, CommandLoading, CommandEmpty, CommandGroup, CommandItem } from '../chunk-PGQXVJXW.js';
3
3
  import '../chunk-IQIJCMG2.js';
4
4
  import { Button } from '../chunk-GHKTVHQG.js';
@@ -111,8 +111,19 @@ type EventDetailPanelProps = {
111
111
  /** The hype tier, rendered as given (the app's own badge) in the chip row. */
112
112
  hype?: React.ReactNode;
113
113
  venue?: EventDetailVenue;
114
- /** Activity tags, after status, fee and hype. */
115
- tags?: string[];
114
+ /** Activity tags. Pass a destination to make a tag a browse action. */
115
+ tags?: (string | {
116
+ label: string;
117
+ href: string;
118
+ onClick?: () => void;
119
+ })[];
120
+ /** Entry information opened by the price/free-entry control. */
121
+ entryDetails?: {
122
+ label: string;
123
+ description: string;
124
+ action?: React.ReactNode;
125
+ onOpenChange?: (open: boolean) => void;
126
+ };
116
127
  /** Performer names, in the order the API gave them. */
117
128
  performers?: string[];
118
129
  /** How many performers to show before the "show all" chip. Default 5. */
@@ -137,7 +148,7 @@ type EventDetailPanelProps = {
137
148
  /** Rendered instead of the poster when it's absent. Defaults to `<EventPosterFallback />`. */
138
149
  fallback?: React.ReactNode;
139
150
  };
140
- declare function EventDetailPanel({ event, labels, formatters, dateLine, dateTime, status, soonLabel, hype, venue, tags, performers, performersPreview, showAllPerformersLabel, headerActions, footer, externalLink, heroHeight, size, linkComponent: LinkComponent, className, fallback, }: EventDetailPanelProps): react_jsx_runtime.JSX.Element;
151
+ declare function EventDetailPanel({ event, labels, formatters, dateLine, dateTime, status, soonLabel, hype, venue, tags, entryDetails, performers, performersPreview, showAllPerformersLabel, headerActions, footer, externalLink, heroHeight, size, linkComponent: LinkComponent, className, fallback, }: EventDetailPanelProps): react_jsx_runtime.JSX.Element;
141
152
  type EventDetailFooterProps = {
142
153
  /**
143
154
  * The one primary action — a `Button` (reserve, tickets, directions when
@@ -205,17 +216,17 @@ type EventDetailPanelSkeletonProps = {
205
216
  };
206
217
  /** Mirrors `<EventDetailPanel>`'s geometry: capped hero, two title lines, when-line, chips, venue card, line-up, about, ghost row and primary. */
207
218
  declare function EventDetailPanelSkeleton({ size, heroHeight, headerActions, label, className, }: EventDetailPanelSkeletonProps): react_jsx_runtime.JSX.Element;
208
- type EventDetailChipRowProps = Pick<EventDetailPanelProps, "event" | "formatters" | "status" | "soonLabel" | "hype" | "tags"> & {
219
+ type EventDetailChipRowProps = Pick<EventDetailPanelProps, "event" | "formatters" | "status" | "soonLabel" | "hype" | "tags" | "entryDetails" | "linkComponent"> & {
209
220
  /** Only the chip strings — a page rendering the row alone need not name the section headings. */
210
221
  labels: Pick<EventDetailPanelLabels, "free" | "liveNow" | "ended">;
211
222
  className?: string;
212
223
  };
213
224
  /**
214
- * One wrapping row, all 24px: status, fee, hype, then activity tags. Exported
225
+ * One wrapping row: metadata, entry information, then activity links. Exported
215
226
  * so the page renders the same row above its title — it is the panel's row,
216
227
  * not a second one.
217
228
  */
218
- declare function EventDetailChipRow({ event, labels, formatters, status, soonLabel, hype, tags, className, }: EventDetailChipRowProps): react_jsx_runtime.JSX.Element;
229
+ declare function EventDetailChipRow({ event, labels, formatters, status, soonLabel, hype, tags, entryDetails, linkComponent: LinkComponent, className, }: EventDetailChipRowProps): react_jsx_runtime.JSX.Element;
219
230
  type EventDetailVenueCardProps = {
220
231
  venue: EventDetailVenue;
221
232
  labels: Pick<EventDetailPanelLabels, "venueNoPage" | "grade">;
@@ -4,13 +4,14 @@ import { resolveEventEntryFee } from '../chunk-DNSXMHYX.js';
4
4
  import { Separator } from '../chunk-NWZGSLPU.js';
5
5
  import { EventPosterFallback } from '../chunk-FDITZ2VM.js';
6
6
  import { Skeleton } from '../chunk-XBBEX4SF.js';
7
+ import { Popover, PopoverTrigger, PopoverContent } from '../chunk-RXXD3UYP.js';
7
8
  import { Button } from '../chunk-GHKTVHQG.js';
8
9
  import '../chunk-RIH2IS7X.js';
9
10
  import '../chunk-5YNIQ2BL.js';
10
11
  import { cn } from '../chunk-FEK5XGZW.js';
11
12
  import { __spreadProps, __spreadValues, __objRest } from '../chunk-MMUBH76A.js';
12
13
  import * as React from 'react';
13
- import { Calendar, User, CalendarX, Unplug, RefreshCw, Timer, Gift, Ticket, MapPin, Star, ChevronRight } from 'lucide-react';
14
+ import { Calendar, User, CalendarX, Unplug, RefreshCw, Gift, Ticket, Timer, ChevronRight, MapPin, Star } from 'lucide-react';
14
15
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
15
16
 
16
17
  function DefaultLink(_a) {
@@ -34,6 +35,7 @@ function EventDetailPanel({
34
35
  hype,
35
36
  venue,
36
37
  tags,
38
+ entryDetails,
37
39
  performers,
38
40
  performersPreview = 5,
39
41
  showAllPerformersLabel,
@@ -122,7 +124,9 @@ function EventDetailPanel({
122
124
  status,
123
125
  soonLabel,
124
126
  hype,
125
- tags
127
+ tags,
128
+ entryDetails,
129
+ linkComponent: LinkComponent
126
130
  }
127
131
  ),
128
132
  venue && /* @__PURE__ */ jsxs("div", { children: [
@@ -396,10 +400,14 @@ function EventDetailChipRow({
396
400
  soonLabel,
397
401
  hype,
398
402
  tags,
403
+ entryDetails,
404
+ linkComponent: LinkComponent = DefaultLink,
399
405
  className
400
406
  }) {
401
407
  const fee = resolveEventEntryFee(event);
402
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap gap-[7px]", className), children: [
408
+ const priceLabel = fee.kind === "free" ? labels.free : fee.kind === "paid" ? formatters.price(fee.amountRon) : null;
409
+ const priceIcon = fee.kind === "free" ? /* @__PURE__ */ jsx(Gift, { className: "h-3.5 w-3.5", "aria-hidden": true }) : /* @__PURE__ */ jsx(Ticket, { className: "h-3.5 w-3.5", "aria-hidden": true });
410
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center gap-[7px]", className), children: [
403
411
  status === "live" && /* @__PURE__ */ jsxs(
404
412
  "span",
405
413
  {
@@ -436,7 +444,35 @@ function EventDetailChipRow({
436
444
  children: labels.ended
437
445
  }
438
446
  ),
439
- fee.kind === "free" && /* @__PURE__ */ jsxs(
447
+ priceLabel && entryDetails ? /* @__PURE__ */ jsxs(Popover, { onOpenChange: entryDetails.onOpenChange, children: [
448
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
449
+ Button,
450
+ {
451
+ variant: "outline",
452
+ size: "sm",
453
+ className: "min-h-11 rounded-full",
454
+ "aria-label": entryDetails.label,
455
+ children: [
456
+ priceIcon,
457
+ priceLabel,
458
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5", "aria-hidden": true })
459
+ ]
460
+ }
461
+ ) }),
462
+ /* @__PURE__ */ jsxs(
463
+ PopoverContent,
464
+ {
465
+ align: "start",
466
+ "aria-label": entryDetails.label,
467
+ className: "flex max-w-[calc(100vw-2rem)] flex-col gap-3",
468
+ children: [
469
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: priceLabel }),
470
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: entryDetails.description }),
471
+ entryDetails.action
472
+ ]
473
+ }
474
+ )
475
+ ] }) : fee.kind === "free" ? /* @__PURE__ */ jsxs(
440
476
  "span",
441
477
  {
442
478
  className: cn(
@@ -448,13 +484,27 @@ function EventDetailChipRow({
448
484
  labels.free
449
485
  ]
450
486
  }
451
- ),
452
- fee.kind === "paid" && /* @__PURE__ */ jsxs("span", { className: cn(CHIP, "text-foreground"), children: [
487
+ ) : fee.kind === "paid" ? /* @__PURE__ */ jsxs("span", { className: cn(CHIP, "text-foreground"), children: [
453
488
  /* @__PURE__ */ jsx(Ticket, { className: "h-3 w-3", "aria-hidden": true }),
454
489
  formatters.price(fee.amountRon)
455
- ] }),
490
+ ] }) : null,
456
491
  hype,
457
- tags == null ? void 0 : tags.map((tag) => /* @__PURE__ */ jsx("span", { className: CHIP, children: tag }, tag))
492
+ tags == null ? void 0 : tags.map(
493
+ (tag) => typeof tag === "string" ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: tag }, tag) : /* @__PURE__ */ jsx(
494
+ Button,
495
+ {
496
+ asChild: true,
497
+ variant: "outline",
498
+ size: "sm",
499
+ className: "min-h-11 rounded-full",
500
+ children: /* @__PURE__ */ jsxs(LinkComponent, { href: tag.href, onClick: tag.onClick, children: [
501
+ tag.label,
502
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5", "aria-hidden": true })
503
+ ] })
504
+ },
505
+ tag.href
506
+ )
507
+ )
458
508
  ] });
459
509
  }
460
510
  function EventDetailVenueCard({
@@ -58,6 +58,12 @@ type FacetGroupProps = Omit<ComponentPropsWithoutRef<"fieldset">, "title" | "chi
58
58
  */
59
59
  name?: string;
60
60
  size?: FacetGroupSize;
61
+ /** Wrapping native-input chips for filter panels. Rows remain the default. */
62
+ layout?: "rows" | "chips";
63
+ /** Optional bounded chip list; selected options always stay visible. */
64
+ visibleLimit?: number;
65
+ showAllLabel?: string | ((count: number) => string);
66
+ showLessLabel?: string;
61
67
  /**
62
68
  * Turns the legend into a disclosure toggle for this group's options.
63
69
  *
@@ -84,7 +90,7 @@ type FacetGroupProps = Omit<ComponentPropsWithoutRef<"fieldset">, "title" | "chi
84
90
  moreExpanded?: boolean;
85
91
  className?: string;
86
92
  };
87
- declare function FacetGroup({ title, icon: Icon, options, selection, name, size, collapsible, defaultOpen, onToggle, moreLabel, onMore, moreExpanded, className, ...rest }: FacetGroupProps): react_jsx_runtime.JSX.Element;
93
+ declare function FacetGroup({ title, icon: Icon, options, selection, name, size, layout, visibleLimit, showAllLabel, showLessLabel, collapsible, defaultOpen, onToggle, moreLabel, onMore, moreExpanded, className, ...rest }: FacetGroupProps): react_jsx_runtime.JSX.Element;
88
94
  type FacetGroupSkeletonProps = {
89
95
  /** How many option rows to draw — match the expected/last-known option count. */
90
96
  optionCount?: number;
@@ -92,9 +98,10 @@ type FacetGroupSkeletonProps = {
92
98
  showMore?: boolean;
93
99
  /** Must match the `<FacetGroup>` it stands in for, or rows shift when data lands. */
94
100
  size?: FacetGroupSize;
101
+ layout?: "rows" | "chips";
95
102
  className?: string;
96
103
  };
97
104
  /** Mirrors `<FacetGroup>`'s geometry exactly so nothing shifts when data lands. */
98
- declare function FacetGroupSkeleton({ optionCount, showMore, size, className, }: FacetGroupSkeletonProps): react_jsx_runtime.JSX.Element;
105
+ declare function FacetGroupSkeleton({ optionCount, showMore, size, className, layout, }: FacetGroupSkeletonProps): react_jsx_runtime.JSX.Element;
99
106
 
100
107
  export { FacetGroup, type FacetGroupProps, type FacetGroupSelection, type FacetGroupSize, FacetGroupSkeleton, type FacetGroupSkeletonProps, type FacetOption };