From 9256369926d7d98784c3d60b928f7b111dc9e3f9 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 2 May 2026 22:46:29 -0400 Subject: [PATCH] feat(web): TrackMenuItem primitive for M7 #372 Single-entry button used by TrackMenu. Supports aria-disabled (kept visible to preserve menu height when admin-only or pre-#352 entries are non-functional) and a `danger` flag for the oxblood-tinted "Remove from library" entry. --- web/src/lib/components/TrackMenuItem.svelte | 43 ++++++++++++++++++++ web/src/lib/components/TrackMenuItem.test.ts | 27 ++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 web/src/lib/components/TrackMenuItem.svelte create mode 100644 web/src/lib/components/TrackMenuItem.test.ts diff --git a/web/src/lib/components/TrackMenuItem.svelte b/web/src/lib/components/TrackMenuItem.svelte new file mode 100644 index 00000000..d7c2377e --- /dev/null +++ b/web/src/lib/components/TrackMenuItem.svelte @@ -0,0 +1,43 @@ + + + diff --git a/web/src/lib/components/TrackMenuItem.test.ts b/web/src/lib/components/TrackMenuItem.test.ts new file mode 100644 index 00000000..eddee16b --- /dev/null +++ b/web/src/lib/components/TrackMenuItem.test.ts @@ -0,0 +1,27 @@ +import { describe, test, expect, vi } from 'vitest'; +import { render, fireEvent, screen } from '@testing-library/svelte'; +import { Music2 } from 'lucide-svelte'; +import TrackMenuItem from './TrackMenuItem.svelte'; + +describe('TrackMenuItem', () => { + test('renders icon, label, and fires onclick', async () => { + const onclick = vi.fn(); + render(TrackMenuItem, { props: { icon: Music2, label: 'Play next', onclick } }); + const btn = screen.getByRole('menuitem', { name: /play next/i }); + await fireEvent.click(btn); + expect(onclick).toHaveBeenCalledOnce(); + expect(btn.getAttribute('aria-disabled')).toBe('false'); + }); + + test('aria-disabled blocks onclick and reflects in DOM', async () => { + const onclick = vi.fn(); + render(TrackMenuItem, { + props: { icon: Music2, label: 'Add to playlist…', onclick, disabled: true, title: 'Coming with playlists' }, + }); + const btn = screen.getByRole('menuitem', { name: /add to playlist/i }); + expect(btn.getAttribute('aria-disabled')).toBe('true'); + expect(btn.getAttribute('title')).toBe('Coming with playlists'); + await fireEvent.click(btn); + expect(onclick).not.toHaveBeenCalled(); + }); +});