@bearmenu/ui 0.8.3 → 0.8.6
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/dist/chunk-2WDJR6K7.js +76 -0
- package/dist/chunk-637L7XQ3.js +85 -0
- package/dist/chunk-6XMYEZVR.js +26 -0
- package/dist/chunk-DNSXMHYX.js +8 -0
- package/dist/chunk-FDITZ2VM.js +16 -0
- package/dist/chunk-GPH6L4DX.js +55 -0
- package/dist/{chunk-N2KNBPAQ.js → chunk-QXHMPJ35.js} +1 -0
- package/dist/chunk-TT3WFS6S.js +379 -0
- package/dist/chunk-UXWAOISG.js +170 -0
- package/dist/{chunk-UZ3PCIE5.js → chunk-XWMRABZW.js} +2 -2
- package/dist/{chunk-VBA45GLP.js → chunk-ZDAHKI3A.js} +12 -2
- package/dist/components/alert.d.ts +2 -2
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/card.d.ts +2 -2
- package/dist/components/card.js +4 -127
- package/dist/components/category-deck.d.ts +50 -0
- package/dist/components/category-deck.js +128 -0
- package/dist/components/command.d.ts +15 -15
- package/dist/components/concept-card.d.ts +43 -0
- package/dist/components/concept-card.js +81 -0
- package/dist/components/coverflow.d.ts +123 -0
- package/dist/components/coverflow.js +300 -0
- package/dist/components/date-input.d.ts +1 -1
- package/dist/components/day-rail-chip.d.ts +82 -0
- package/dist/components/day-rail-chip.js +105 -0
- package/dist/components/drift-rail.d.ts +28 -0
- package/dist/components/drift-rail.js +3 -0
- package/dist/components/event-card.d.ts +97 -0
- package/dist/components/event-card.js +161 -0
- package/dist/components/event-compact-row.d.ts +72 -0
- package/dist/components/event-compact-row.js +133 -0
- package/dist/components/event-day-header.d.ts +65 -0
- package/dist/components/event-day-header.js +95 -0
- package/dist/components/event-day-separator.d.ts +46 -0
- package/dist/components/event-day-separator.js +50 -0
- package/dist/components/event-detail-panel.d.ts +80 -0
- package/dist/components/event-detail-panel.js +251 -0
- package/dist/components/event-hub-hero.d.ts +34 -0
- package/dist/components/event-hub-hero.js +57 -0
- package/dist/components/event-index-row.d.ts +68 -0
- package/dist/components/event-index-row.js +84 -0
- package/dist/components/event-list-row-wide.d.ts +101 -0
- package/dist/components/event-list-row-wide.js +218 -0
- package/dist/components/event-list-row.d.ts +82 -0
- package/dist/components/event-list-row.js +173 -0
- package/dist/components/event-poster-fallback.d.ts +20 -0
- package/dist/components/event-poster-fallback.js +3 -0
- package/dist/components/event-types.d.ts +118 -0
- package/dist/components/event-types.js +2 -0
- package/dist/components/events-empty-state.d.ts +44 -0
- package/dist/components/events-empty-state.js +73 -0
- package/dist/components/facet-group.d.ts +93 -0
- package/dist/components/facet-group.js +222 -0
- package/dist/components/featured-rail-item.d.ts +42 -0
- package/dist/components/featured-rail-item.js +88 -0
- package/dist/components/hour-band.d.ts +68 -0
- package/dist/components/hour-band.js +53 -0
- package/dist/components/hour-group.d.ts +67 -0
- package/dist/components/hour-group.js +59 -0
- package/dist/components/icon.d.ts +18 -0
- package/dist/components/icon.js +31 -0
- package/dist/components/item.d.ts +2 -2
- package/dist/components/motion-icon-controls.d.ts +26 -0
- package/dist/components/motion-icon-controls.js +4 -0
- package/dist/components/motion-icon-set.d.ts +27 -0
- package/dist/components/motion-icon-set.js +139 -0
- package/dist/components/motion-icon.d.ts +44 -0
- package/dist/components/motion-icon.js +3 -0
- package/dist/components/multi-select-combobox.js +1 -1
- package/dist/components/place-about-tab.js +3 -3
- package/dist/components/place-details-mobile.js +3 -3
- package/dist/components/poster-stack.d.ts +30 -0
- package/dist/components/poster-stack.js +104 -0
- package/dist/components/poster-tape.d.ts +36 -0
- package/dist/components/poster-tape.js +64 -0
- package/dist/components/poster-wall.d.ts +25 -0
- package/dist/components/poster-wall.js +183 -0
- package/dist/components/quiet-stretch.d.ts +43 -0
- package/dist/components/quiet-stretch.js +54 -0
- package/dist/components/section-header.d.ts +53 -0
- package/dist/components/section-header.js +63 -0
- package/dist/components/segmented-nav.d.ts +62 -0
- package/dist/components/segmented-nav.js +54 -0
- package/dist/components/skeleton-card.js +1 -1
- package/dist/components/skeleton.d.ts +17 -0
- package/dist/components/skeleton.js +1 -1
- package/dist/components/spinner.d.ts +2 -2
- package/dist/components/tag-group.js +3 -26
- package/dist/components/tag.d.ts +2 -2
- package/dist/components/tag.js +1 -1
- package/dist/components/text.d.ts +3 -3
- package/dist/components/timeline-band.d.ts +46 -0
- package/dist/components/timeline-band.js +5 -0
- package/dist/components/venue-events-block.d.ts +143 -0
- package/dist/components/venue-events-block.js +222 -0
- package/dist/components/weekend-panel.d.ts +44 -0
- package/dist/components/weekend-panel.js +231 -0
- package/dist/lib/icon-registry.d.ts +58 -0
- package/dist/lib/icon-registry.js +39 -0
- package/package.json +2 -1
- package/src/components/accordion.stories.tsx +1 -1
- package/src/components/card.tsx +44 -1
- package/src/components/category-deck.stories.tsx +96 -0
- package/src/components/category-deck.tsx +227 -0
- package/src/components/combobox.stories.tsx +1 -1
- package/src/components/concept-card.stories.tsx +80 -0
- package/src/components/concept-card.tsx +143 -0
- package/src/components/coverflow.stories.tsx +240 -0
- package/src/components/coverflow.test.tsx +193 -0
- package/src/components/coverflow.tsx +550 -0
- package/src/components/currency-input.stories.tsx +3 -3
- package/src/components/day-rail-chip.stories.tsx +145 -0
- package/src/components/day-rail-chip.tsx +201 -0
- package/src/components/drift-rail.stories.tsx +92 -0
- package/src/components/drift-rail.tsx +86 -0
- package/src/components/empty-state.stories.tsx +3 -3
- package/src/components/event-card.stories.tsx +248 -0
- package/src/components/event-card.test.tsx +177 -0
- package/src/components/event-card.tsx +321 -0
- package/src/components/event-compact-row.stories.tsx +221 -0
- package/src/components/event-compact-row.tsx +268 -0
- package/src/components/event-day-header.stories.tsx +124 -0
- package/src/components/event-day-header.tsx +180 -0
- package/src/components/event-day-separator.stories.tsx +70 -0
- package/src/components/event-day-separator.tsx +95 -0
- package/src/components/event-detail-panel.stories.tsx +191 -0
- package/src/components/event-detail-panel.tsx +360 -0
- package/src/components/event-hub-hero.stories.tsx +66 -0
- package/src/components/event-hub-hero.tsx +110 -0
- package/src/components/event-index-row.stories.tsx +116 -0
- package/src/components/event-index-row.tsx +181 -0
- package/src/components/event-list-row-wide.stories.tsx +204 -0
- package/src/components/event-list-row-wide.tsx +386 -0
- package/src/components/event-list-row.stories.tsx +159 -0
- package/src/components/event-list-row.tsx +335 -0
- package/src/components/event-poster-fallback.stories.tsx +52 -0
- package/src/components/event-poster-fallback.tsx +31 -0
- package/src/components/event-types.ts +133 -0
- package/src/components/events-empty-state.stories.tsx +59 -0
- package/src/components/events-empty-state.tsx +131 -0
- package/src/components/facet-group.stories.tsx +247 -0
- package/src/components/facet-group.test.tsx +225 -0
- package/src/components/facet-group.tsx +352 -0
- package/src/components/featured-rail-item.stories.tsx +86 -0
- package/src/components/featured-rail-item.tsx +153 -0
- package/src/components/form.stories.tsx +1 -1
- package/src/components/hour-band.stories.tsx +159 -0
- package/src/components/hour-band.tsx +126 -0
- package/src/components/hour-group.stories.tsx +100 -0
- package/src/components/hour-group.tsx +124 -0
- package/src/components/icon.tsx +57 -0
- package/src/components/input-otp.stories.tsx +1 -1
- package/src/components/markdown-renderer.stories.tsx +1 -1
- package/src/components/motion-icon-controls.test.tsx +78 -0
- package/src/components/motion-icon-controls.tsx +552 -0
- package/src/components/motion-icon-set.stories.tsx +185 -0
- package/src/components/motion-icon-set.tsx +219 -0
- package/src/components/motion-icon.test.tsx +159 -0
- package/src/components/motion-icon.tsx +163 -0
- package/src/components/multi-select-combobox.stories.tsx +1 -1
- package/src/components/phone-frame.stories.tsx +1 -1
- package/src/components/poster-stack.stories.tsx +68 -0
- package/src/components/poster-stack.tsx +155 -0
- package/src/components/poster-tape.stories.tsx +70 -0
- package/src/components/poster-tape.tsx +122 -0
- package/src/components/poster-wall.stories.tsx +95 -0
- package/src/components/poster-wall.tsx +220 -0
- package/src/components/quiet-stretch.stories.tsx +62 -0
- package/src/components/quiet-stretch.tsx +115 -0
- package/src/components/rating.stories.tsx +3 -3
- package/src/components/searchable-select.stories.tsx +1 -1
- package/src/components/section-header.stories.tsx +70 -0
- package/src/components/section-header.tsx +134 -0
- package/src/components/segmented-nav.stories.tsx +118 -0
- package/src/components/segmented-nav.tsx +113 -0
- package/src/components/selection-bar.stories.tsx +1 -1
- package/src/components/skeleton-card.stories.tsx +3 -3
- package/src/components/skeleton.tsx +18 -0
- package/src/components/sliding-panels.stories.tsx +1 -1
- package/src/components/stepper.stories.tsx +1 -1
- package/src/components/sticky-container.stories.tsx +3 -3
- package/src/components/tag.tsx +11 -1
- package/src/components/timeline-band.stories.tsx +206 -0
- package/src/components/timeline-band.tsx +207 -0
- package/src/components/toggle-group.stories.tsx +1 -1
- package/src/components/tooltip.stories.tsx +2 -2
- package/src/components/venue-events-block.stories.tsx +216 -0
- package/src/components/venue-events-block.tsx +408 -0
- package/src/components/weekend-panel.stories.tsx +92 -0
- package/src/components/weekend-panel.tsx +322 -0
- package/src/globals.css +19 -0
- package/src/lib/icon-registry.ts +139 -0
- package/src/test/setup.ts +5 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import { Coverflow, type CoverflowItem } from "./coverflow";
|
|
5
|
+
|
|
6
|
+
const items = (count: number): CoverflowItem[] =>
|
|
7
|
+
Array.from({ length: count }, (_, index) => ({
|
|
8
|
+
id: `e${index}`,
|
|
9
|
+
title: `Event ${index}`,
|
|
10
|
+
meta: `Meta ${index}`,
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const renderCoverflow = (props: Partial<React.ComponentProps<typeof Coverflow>> = {}) =>
|
|
14
|
+
render(
|
|
15
|
+
<Coverflow
|
|
16
|
+
items={items(7)}
|
|
17
|
+
activeIndex={0}
|
|
18
|
+
freeLabel="Free"
|
|
19
|
+
prevLabel="Previous"
|
|
20
|
+
nextLabel="Next"
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
/** Every card is named by its title, so the mounted set is readable from the roles. */
|
|
26
|
+
const mountedTitles = () =>
|
|
27
|
+
screen.getAllByRole("button").map((node) => node.getAttribute("aria-label"));
|
|
28
|
+
|
|
29
|
+
describe("Coverflow", () => {
|
|
30
|
+
describe("the ring", () => {
|
|
31
|
+
// The reported defect: at activeIndex 0 nothing had a negative offset, so
|
|
32
|
+
// the left half of the stage was empty while three cards stacked right.
|
|
33
|
+
it("fills both flanks at activeIndex 0", () => {
|
|
34
|
+
renderCoverflow({ activeIndex: 0 });
|
|
35
|
+
|
|
36
|
+
// 7 items, visible window |offset| <= 3 — the whole ring is on stage,
|
|
37
|
+
// items 4/5/6 having wrapped round to offsets -3/-2/-1.
|
|
38
|
+
const titles = mountedTitles().filter((title) => title !== "Previous" && title !== "Next");
|
|
39
|
+
expect(titles).toEqual(expect.arrayContaining(["Event 4", "Event 5", "Event 6"]));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("steps backwards from 0 to the last index instead of clamping", async () => {
|
|
43
|
+
const onActiveIndexChange = vi.fn();
|
|
44
|
+
renderCoverflow({ activeIndex: 0, onActiveIndexChange });
|
|
45
|
+
|
|
46
|
+
await userEvent.click(screen.getByRole("button", { name: "Previous" }));
|
|
47
|
+
expect(onActiveIndexChange).toHaveBeenCalledWith(6);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("steps forwards from the last index back to 0 instead of clamping", async () => {
|
|
51
|
+
const onActiveIndexChange = vi.fn();
|
|
52
|
+
renderCoverflow({ activeIndex: 6, onActiveIndexChange });
|
|
53
|
+
|
|
54
|
+
await userEvent.click(screen.getByRole("button", { name: "Next" }));
|
|
55
|
+
expect(onActiveIndexChange).toHaveBeenCalledWith(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("reports the index of the side poster that was clicked", async () => {
|
|
59
|
+
const onActiveIndexChange = vi.fn();
|
|
60
|
+
renderCoverflow({ activeIndex: 0, onActiveIndexChange });
|
|
61
|
+
|
|
62
|
+
// Event 6 sits at offset -1, immediately left of the lead.
|
|
63
|
+
await userEvent.click(screen.getByRole("button", { name: "Event 6" }));
|
|
64
|
+
expect(onActiveIndexChange).toHaveBeenCalledWith(6);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("the wrap", () => {
|
|
69
|
+
// The card that comes round the back must NOT tween across the face of the
|
|
70
|
+
// stage. It renders without its transition classes for exactly the commit
|
|
71
|
+
// in which it crosses the seam, so the transform lands instantly.
|
|
72
|
+
it("drops the transition only on the card crossing the seam", () => {
|
|
73
|
+
const ring = items(7);
|
|
74
|
+
const { rerender } = renderCoverflow({ items: ring, activeIndex: 0 });
|
|
75
|
+
|
|
76
|
+
const transitionClass = "transition-[transform,box-shadow]";
|
|
77
|
+
expect(screen.getByRole("button", { name: "Event 4" }).className).toContain(transitionClass);
|
|
78
|
+
|
|
79
|
+
// Advancing by one sends Event 4 from offset -3 to offset +3 the short
|
|
80
|
+
// way round, while Event 6 merely slides from -1 to -2.
|
|
81
|
+
rerender(
|
|
82
|
+
<Coverflow
|
|
83
|
+
items={ring}
|
|
84
|
+
activeIndex={1}
|
|
85
|
+
freeLabel="Free"
|
|
86
|
+
prevLabel="Previous"
|
|
87
|
+
nextLabel="Next"
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(screen.getByRole("button", { name: "Event 4" }).className).not.toContain(
|
|
92
|
+
transitionClass
|
|
93
|
+
);
|
|
94
|
+
expect(screen.getByRole("button", { name: "Event 6" }).className).toContain(transitionClass);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("keeps the transition on every card when the lead jumps several slots at once", () => {
|
|
98
|
+
const ring = items(20);
|
|
99
|
+
const { rerender } = renderCoverflow({ items: ring, activeIndex: 5 });
|
|
100
|
+
|
|
101
|
+
rerender(
|
|
102
|
+
<Coverflow
|
|
103
|
+
items={ring}
|
|
104
|
+
activeIndex={8}
|
|
105
|
+
freeLabel="Free"
|
|
106
|
+
prevLabel="Previous"
|
|
107
|
+
nextLabel="Next"
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// A three-slot jump (clicking the outermost side poster) moves every card
|
|
112
|
+
// by three — nothing crossed the seam, so nothing may pop.
|
|
113
|
+
expect(screen.getByRole("button", { name: "Event 5" }).className).toContain(
|
|
114
|
+
"transition-[transform,box-shadow]"
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("the visible window", () => {
|
|
120
|
+
// A 50-item ring must not paint 50 posters just because every item now
|
|
121
|
+
// resolves to some offset.
|
|
122
|
+
it("mounts only the cards within three slots of the lead", () => {
|
|
123
|
+
renderCoverflow({ items: items(50), activeIndex: 0 });
|
|
124
|
+
|
|
125
|
+
const titles = mountedTitles().filter((title) => title !== "Previous" && title !== "Next");
|
|
126
|
+
expect(titles).toHaveLength(7);
|
|
127
|
+
expect(titles).toEqual(
|
|
128
|
+
expect.arrayContaining([
|
|
129
|
+
"Event 47",
|
|
130
|
+
"Event 48",
|
|
131
|
+
"Event 49",
|
|
132
|
+
"Event 0",
|
|
133
|
+
"Event 1",
|
|
134
|
+
"Event 2",
|
|
135
|
+
"Event 3",
|
|
136
|
+
])
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("degenerate lengths", () => {
|
|
142
|
+
it("renders nothing at all for an empty list", () => {
|
|
143
|
+
const { container } = renderCoverflow({ items: [] });
|
|
144
|
+
expect(container).toBeEmptyDOMElement();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// A control that looks operable and does nothing is the bug the component's
|
|
148
|
+
// own docblock argues against — with one item there is nowhere to step to.
|
|
149
|
+
it("renders no arrows for a single item", () => {
|
|
150
|
+
renderCoverflow({ items: items(1) });
|
|
151
|
+
|
|
152
|
+
expect(screen.queryByRole("button", { name: "Previous" })).not.toBeInTheDocument();
|
|
153
|
+
expect(screen.queryByRole("button", { name: "Next" })).not.toBeInTheDocument();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("keeps the two-item ring's second card on one consistent side", () => {
|
|
157
|
+
const { rerender } = renderCoverflow({ items: items(2), activeIndex: 0 });
|
|
158
|
+
const at0 = screen.getByRole("button", { name: "Event 1" }).getAttribute("style");
|
|
159
|
+
|
|
160
|
+
rerender(
|
|
161
|
+
<Coverflow
|
|
162
|
+
items={items(2)}
|
|
163
|
+
activeIndex={1}
|
|
164
|
+
freeLabel="Free"
|
|
165
|
+
prevLabel="Previous"
|
|
166
|
+
nextLabel="Next"
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
const at1 = screen.getByRole("button", { name: "Event 0" }).getAttribute("style");
|
|
170
|
+
|
|
171
|
+
// Whichever card is not the lead resolves the n/2 tie the same way, so
|
|
172
|
+
// both renders put it in the identical right-flank slot rather than
|
|
173
|
+
// flipping it between the two flanks.
|
|
174
|
+
expect(at0).toBe(at1);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("caption and position", () => {
|
|
179
|
+
it("renders the position on its own, with no separator dot, when there is no caption", () => {
|
|
180
|
+
renderCoverflow({ positionLabel: "1 of 7" });
|
|
181
|
+
|
|
182
|
+
expect(screen.getByText("1 of 7")).toBeInTheDocument();
|
|
183
|
+
expect(screen.queryByText("·")).not.toBeInTheDocument();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("separates the two only when both are given", () => {
|
|
187
|
+
renderCoverflow({ caption: "7 events", positionLabel: "1 of 7" });
|
|
188
|
+
|
|
189
|
+
expect(screen.getByText("7 events")).toBeInTheDocument();
|
|
190
|
+
expect(screen.getByText("·")).toBeInTheDocument();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|