Skip to content

Commit ace2e9d

Browse files
committed
init
1 parent d93334a commit ace2e9d

9 files changed

Lines changed: 1283 additions & 9 deletions

File tree

Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
<script lang="ts">
2+
import { ContextMenu, DropdownMenu } from "bits-ui";
3+
import CaretRight from "phosphor-svelte/lib/CaretRight";
4+
import DotsThree from "phosphor-svelte/lib/DotsThree";
5+
import FunnelSimple from "phosphor-svelte/lib/FunnelSimple";
6+
import MouseSimple from "phosphor-svelte/lib/MouseSimple";
7+
8+
let debugMode = $state(true);
9+
let openDelay = $state(80);
10+
let selectedStatus = $state("icebox");
11+
let selectedPriority = $state("p1");
12+
let selectedLabel = $state("strategic-initiative");
13+
let selectedLead = $state("hunter");
14+
const debugRootProps = $derived.by(() => ({ debugMode }) as any);
15+
16+
const statusItems = [
17+
{ value: "icebox", label: "Icebox" },
18+
{ value: "backlog", label: "Backlog" },
19+
{ value: "todo", label: "Todo" },
20+
{ value: "in-progress", label: "In Progress" },
21+
{ value: "done", label: "Done" },
22+
];
23+
24+
const priorityItems = [
25+
{ value: "p0", label: "P0 - Critical" },
26+
{ value: "p1", label: "P1 - High" },
27+
{ value: "p2", label: "P2 - Medium" },
28+
{ value: "p3", label: "P3 - Low" },
29+
];
30+
31+
const labelItems = [
32+
{ value: "strategic-initiative", label: "Strategic Initiative" },
33+
{ value: "customer-facing", label: "Customer Facing" },
34+
{ value: "internal-tooling", label: "Internal Tooling" },
35+
{ value: "technical-debt", label: "Technical Debt" },
36+
{ value: "revenue-impact", label: "Revenue Impact" },
37+
{ value: "cost-reduction", label: "Cost Reduction" },
38+
{ value: "compliance", label: "Compliance" },
39+
{ value: "platform", label: "Platform" },
40+
{ value: "infrastructure", label: "Infrastructure" },
41+
{ value: "growth", label: "Growth" },
42+
];
43+
44+
const leadItems = [
45+
{ value: "hunter", label: "@huntabyte" },
46+
{ value: "pavel", label: "@pavel_stianko" },
47+
{ value: "adrian", label: "@cokakoala_" },
48+
{ value: "thomas", label: "@thomasglopes" },
49+
];
50+
51+
const triggerClass =
52+
"border-input text-foreground shadow-btn hover:bg-muted inline-flex h-10 select-none items-center justify-center rounded-full border px-4 text-sm font-medium active:scale-[0.98]";
53+
const contentClass =
54+
"border-muted bg-background shadow-popover outline-hidden focus-visible:outline-hidden w-[250px] rounded-xl border px-1 py-1.5";
55+
const subContentClass =
56+
"border-muted bg-background shadow-popover outline-hidden focus-visible:outline-hidden z-100 w-[230px] rounded-xl border px-1 py-1.5";
57+
const itemClass =
58+
"rounded-button data-highlighted:bg-muted ring-0! ring-transparent! flex h-10 select-none items-center py-3 pl-3 pr-1.5 text-sm font-medium focus-visible:outline-none";
59+
const subTriggerClass =
60+
"rounded-button data-highlighted:bg-muted data-[state=open]:bg-muted ring-0! ring-transparent! flex h-10 select-none items-center py-3 pl-3 pr-1.5 text-sm font-medium focus-visible:outline-none";
61+
</script>
62+
63+
<div class="mx-auto flex w-full max-w-[980px] flex-col gap-6 p-6">
64+
<div class="border-muted bg-background shadow-popover rounded-xl border p-4">
65+
<div class="mb-4 flex items-center justify-between gap-3">
66+
<div>
67+
<p class="text-foreground text-sm font-semibold">submenu intent sandbox</p>
68+
<p class="text-muted-foreground text-xs">
69+
Use this page to stress nested submenu transitions and safe-area debug overlays.
70+
</p>
71+
</div>
72+
<div
73+
class="text-muted-foreground rounded-button bg-muted px-2.5 py-1.5 text-xs font-medium"
74+
>
75+
depth: 4 levels
76+
</div>
77+
</div>
78+
79+
<div class="grid gap-3 md:grid-cols-2">
80+
<label
81+
class="border-input rounded-button flex items-center gap-3 border px-3 py-2 text-sm"
82+
>
83+
<input type="checkbox" bind:checked={debugMode} class="size-4" />
84+
<span class="font-medium">debugMode</span>
85+
<span class="text-muted-foreground ml-auto text-xs">{debugMode ? "on" : "off"}</span
86+
>
87+
</label>
88+
89+
<label
90+
class="border-input rounded-button flex items-center gap-3 border px-3 py-2 text-sm"
91+
>
92+
<span class="font-medium">openDelay</span>
93+
<input
94+
type="range"
95+
min={0}
96+
max={400}
97+
step={20}
98+
bind:value={openDelay}
99+
class="w-full"
100+
/>
101+
<span class="text-muted-foreground min-w-[55px] text-right text-xs"
102+
>{openDelay}ms</span
103+
>
104+
</label>
105+
</div>
106+
</div>
107+
108+
<div class="grid gap-6 lg:grid-cols-2">
109+
<section class="border-muted bg-background rounded-xl border p-5">
110+
<div class="mb-4 flex items-center gap-2">
111+
<FunnelSimple class="text-foreground-alt size-5" />
112+
<h2 class="text-sm font-semibold">dropdown stress test</h2>
113+
</div>
114+
115+
<DropdownMenu.Root {...debugRootProps}>
116+
<DropdownMenu.Trigger class={triggerClass}>
117+
<DotsThree class="size-5" />
118+
<span class="ml-1.5">Filter</span>
119+
</DropdownMenu.Trigger>
120+
<DropdownMenu.Portal>
121+
<DropdownMenu.Content class={contentClass} sideOffset={10}>
122+
<DropdownMenu.Item class={itemClass} disabled
123+
>Search all...</DropdownMenu.Item
124+
>
125+
126+
<DropdownMenu.Sub>
127+
<DropdownMenu.SubTrigger class={subTriggerClass} {openDelay}>
128+
Status
129+
<CaretRight class="text-foreground-alt ml-auto size-4" />
130+
</DropdownMenu.SubTrigger>
131+
<DropdownMenu.Portal>
132+
<DropdownMenu.SubContent class={subContentClass} sideOffset={10}>
133+
<DropdownMenu.RadioGroup bind:value={selectedStatus}>
134+
{#each statusItems as item (item.value)}
135+
<DropdownMenu.RadioItem
136+
value={item.value}
137+
class={itemClass}
138+
>
139+
{#snippet children({ checked })}
140+
{item.label}
141+
{#if checked}
142+
<span class="ml-auto text-xs">selected</span
143+
>
144+
{/if}
145+
{/snippet}
146+
</DropdownMenu.RadioItem>
147+
{/each}
148+
</DropdownMenu.RadioGroup>
149+
</DropdownMenu.SubContent>
150+
</DropdownMenu.Portal>
151+
</DropdownMenu.Sub>
152+
153+
<DropdownMenu.Sub>
154+
<DropdownMenu.SubTrigger class={subTriggerClass} {openDelay}>
155+
Project properties
156+
<CaretRight class="text-foreground-alt ml-auto size-4" />
157+
</DropdownMenu.SubTrigger>
158+
<DropdownMenu.Portal>
159+
<DropdownMenu.SubContent class={subContentClass} sideOffset={10}>
160+
<DropdownMenu.Item class={itemClass}
161+
>Project status</DropdownMenu.Item
162+
>
163+
<DropdownMenu.Item class={itemClass}
164+
>Project status type</DropdownMenu.Item
165+
>
166+
167+
<DropdownMenu.Sub>
168+
<DropdownMenu.SubTrigger
169+
class={subTriggerClass}
170+
{openDelay}
171+
>
172+
Project priority
173+
<CaretRight
174+
class="text-foreground-alt ml-auto size-4"
175+
/>
176+
</DropdownMenu.SubTrigger>
177+
<DropdownMenu.Portal>
178+
<DropdownMenu.SubContent
179+
class={subContentClass}
180+
sideOffset={10}
181+
>
182+
<DropdownMenu.RadioGroup
183+
bind:value={selectedPriority}
184+
>
185+
{#each priorityItems as item (item.value)}
186+
<DropdownMenu.RadioItem
187+
value={item.value}
188+
class={itemClass}
189+
>
190+
{#snippet children({ checked })}
191+
{item.label}
192+
{#if checked}
193+
<span class="ml-auto text-xs"
194+
>selected</span
195+
>
196+
{/if}
197+
{/snippet}
198+
</DropdownMenu.RadioItem>
199+
{/each}
200+
</DropdownMenu.RadioGroup>
201+
</DropdownMenu.SubContent>
202+
</DropdownMenu.Portal>
203+
</DropdownMenu.Sub>
204+
205+
<DropdownMenu.Sub>
206+
<DropdownMenu.SubTrigger
207+
class={subTriggerClass}
208+
{openDelay}
209+
>
210+
Project labels
211+
<CaretRight
212+
class="text-foreground-alt ml-auto size-4"
213+
/>
214+
</DropdownMenu.SubTrigger>
215+
<DropdownMenu.Portal>
216+
<DropdownMenu.SubContent
217+
class={subContentClass}
218+
sideOffset={10}
219+
>
220+
<DropdownMenu.RadioGroup bind:value={selectedLabel}>
221+
{#each labelItems as item (item.value)}
222+
<DropdownMenu.RadioItem
223+
value={item.value}
224+
class={itemClass}
225+
>
226+
{#snippet children({ checked })}
227+
{item.label}
228+
{#if checked}
229+
<span class="ml-auto text-xs"
230+
>selected</span
231+
>
232+
{/if}
233+
{/snippet}
234+
</DropdownMenu.RadioItem>
235+
{/each}
236+
</DropdownMenu.RadioGroup>
237+
238+
<DropdownMenu.Sub>
239+
<DropdownMenu.SubTrigger
240+
class={subTriggerClass}
241+
{openDelay}
242+
>
243+
Infrastructure...
244+
<CaretRight
245+
class="text-foreground-alt ml-auto size-4"
246+
/>
247+
</DropdownMenu.SubTrigger>
248+
<DropdownMenu.Portal>
249+
<DropdownMenu.SubContent
250+
class={subContentClass}
251+
sideOffset={10}
252+
>
253+
<DropdownMenu.Item class={itemClass}
254+
>Kubernetes</DropdownMenu.Item
255+
>
256+
<DropdownMenu.Item class={itemClass}
257+
>Database</DropdownMenu.Item
258+
>
259+
<DropdownMenu.Item class={itemClass}
260+
>CI Pipeline</DropdownMenu.Item
261+
>
262+
<DropdownMenu.Item class={itemClass}
263+
>Observability</DropdownMenu.Item
264+
>
265+
</DropdownMenu.SubContent>
266+
</DropdownMenu.Portal>
267+
</DropdownMenu.Sub>
268+
</DropdownMenu.SubContent>
269+
</DropdownMenu.Portal>
270+
</DropdownMenu.Sub>
271+
272+
<DropdownMenu.Sub>
273+
<DropdownMenu.SubTrigger
274+
class={subTriggerClass}
275+
{openDelay}
276+
>
277+
Project lead
278+
<CaretRight
279+
class="text-foreground-alt ml-auto size-4"
280+
/>
281+
</DropdownMenu.SubTrigger>
282+
<DropdownMenu.Portal>
283+
<DropdownMenu.SubContent
284+
class={subContentClass}
285+
sideOffset={10}
286+
>
287+
<DropdownMenu.RadioGroup bind:value={selectedLead}>
288+
{#each leadItems as item (item.value)}
289+
<DropdownMenu.RadioItem
290+
value={item.value}
291+
class={itemClass}
292+
>
293+
{#snippet children({ checked })}
294+
{item.label}
295+
{#if checked}
296+
<span class="ml-auto text-xs"
297+
>selected</span
298+
>
299+
{/if}
300+
{/snippet}
301+
</DropdownMenu.RadioItem>
302+
{/each}
303+
</DropdownMenu.RadioGroup>
304+
</DropdownMenu.SubContent>
305+
</DropdownMenu.Portal>
306+
</DropdownMenu.Sub>
307+
</DropdownMenu.SubContent>
308+
</DropdownMenu.Portal>
309+
</DropdownMenu.Sub>
310+
</DropdownMenu.Content>
311+
</DropdownMenu.Portal>
312+
</DropdownMenu.Root>
313+
</section>
314+
315+
<section class="border-muted bg-background rounded-xl border p-5">
316+
<div class="mb-4 flex items-center gap-2">
317+
<MouseSimple class="text-foreground-alt size-5" />
318+
<h2 class="text-sm font-semibold">context-menu stress test</h2>
319+
</div>
320+
321+
<ContextMenu.Root {...debugRootProps}>
322+
<ContextMenu.Trigger
323+
class="rounded-card border-input text-muted-foreground flex h-[220px] w-full select-none items-center justify-center border-2 border-dashed bg-transparent text-sm font-semibold"
324+
>
325+
right click in this panel
326+
</ContextMenu.Trigger>
327+
<ContextMenu.Portal>
328+
<ContextMenu.Content class={contentClass}>
329+
<ContextMenu.Item class={itemClass}>Open</ContextMenu.Item>
330+
<ContextMenu.Item class={itemClass}>Rename</ContextMenu.Item>
331+
<ContextMenu.Sub>
332+
<ContextMenu.SubTrigger class={subTriggerClass} {openDelay}>
333+
Move to...
334+
<CaretRight class="text-foreground-alt ml-auto size-4" />
335+
</ContextMenu.SubTrigger>
336+
<ContextMenu.Portal>
337+
<ContextMenu.SubContent class={subContentClass} sideOffset={10}>
338+
<ContextMenu.Item class={itemClass}>Backlog</ContextMenu.Item>
339+
<ContextMenu.Item class={itemClass}
340+
>In Progress</ContextMenu.Item
341+
>
342+
<ContextMenu.Item class={itemClass}>Done</ContextMenu.Item>
343+
<ContextMenu.Sub>
344+
<ContextMenu.SubTrigger class={subTriggerClass} {openDelay}>
345+
Archive...
346+
<CaretRight
347+
class="text-foreground-alt ml-auto size-4"
348+
/>
349+
</ContextMenu.SubTrigger>
350+
<ContextMenu.Portal>
351+
<ContextMenu.SubContent
352+
class={subContentClass}
353+
sideOffset={10}
354+
>
355+
<ContextMenu.Item class={itemClass}
356+
>Q1 2026</ContextMenu.Item
357+
>
358+
<ContextMenu.Item class={itemClass}
359+
>Q2 2026</ContextMenu.Item
360+
>
361+
<ContextMenu.Item class={itemClass}
362+
>Q3 2026</ContextMenu.Item
363+
>
364+
<ContextMenu.Item class={itemClass}
365+
>Q4 2026</ContextMenu.Item
366+
>
367+
</ContextMenu.SubContent>
368+
</ContextMenu.Portal>
369+
</ContextMenu.Sub>
370+
</ContextMenu.SubContent>
371+
</ContextMenu.Portal>
372+
</ContextMenu.Sub>
373+
</ContextMenu.Content>
374+
</ContextMenu.Portal>
375+
</ContextMenu.Root>
376+
</section>
377+
</div>
378+
</div>

packages/bits-ui/src/lib/bits/context-menu/components/context-menu.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
let {
99
open = $bindable(false),
1010
dir = "ltr",
11+
debugMode = false,
1112
onOpenChange = noop,
1213
onOpenChangeComplete = noop,
1314
children,
@@ -16,6 +17,7 @@
1617
const root = MenuRootState.create({
1718
variant: boxWith(() => "context-menu"),
1819
dir: boxWith(() => dir),
20+
debugMode: boxWith(() => debugMode),
1921
onClose: () => {
2022
open = false;
2123
onOpenChange?.(false);

0 commit comments

Comments
 (0)