diff --git a/apps/web/app/tests/test-user-select-none.js b/apps/web/app/tests/test-user-select-none.js new file mode 100644 index 00000000..070c58b1 --- /dev/null +++ b/apps/web/app/tests/test-user-select-none.js @@ -0,0 +1,63 @@ +// Test script to verify user-select: none is working on interactive elements + +import { test, expect } from '@playwright/test'; + +// This test would verify that text selection is disabled on interactive elements +test('Interactive elements should not allow text selection', async ({ page }) => { + // Navigate to the app + await page.goto('http://localhost:3000'); + + // Test buttons - try to select text within them + const buttons = await page.locator('button').all(); + + for (const button of buttons) { + const isVisible = await button.isVisible(); + if (isVisible) { + // Try to select all text in the button + await button.selectText().catch(() => { + // Expected to fail or select nothing due to select-none + }); + + // Check if any text was actually selected + const selection = await page.evaluate(() => window.getSelection().toString()); + + // If the button contains only non-selectable elements, selection should be empty + // This test would pass if our select-none implementation is working + console.log(`Button selection result: "${selection}"`); + } + } + + // Test badges, toggles, tabs, etc. + const interactiveElements = [ + '[data-testid="badge"]', + '[role="tab"]', + '[role="switch"]', + '[role="checkbox"]', + '[role="radio"]', + ]; + + for (const selector of interactiveElements) { + const elements = await page.locator(selector).all(); + + for (const element of elements) { + const isVisible = await element.isVisible(); + if (isVisible) { + await element.selectText().catch(() => { + // Expected to fail due to select-none + }); + + const selection = await page.evaluate(() => window.getSelection().toString()); + console.log(`${selector} selection result: "${selection}"`); + } + } + } +}); + +// Simple manual test instructions +console.log(` +Manual Test Instructions: +1. Open http://localhost:3000 in your browser +2. Try to select text within buttons, badges, tabs, toggles, checkboxes, etc. +3. The text within these interactive elements should not be selectable +4. You should see the cursor change but no text highlighting should occur +`); \ No newline at end of file diff --git a/packages/ui/src/components/accordion.tsx b/packages/ui/src/components/accordion.tsx index 3f90e52f..8d60ed04 100644 --- a/packages/ui/src/components/accordion.tsx +++ b/packages/ui/src/components/accordion.tsx @@ -26,7 +26,7 @@ const AccordionTrigger = React.forwardRef< svg]:rotate-180', + 'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all [&[data-state=open]>svg]:rotate-180 select-none', className, )} ref={ref} diff --git a/packages/ui/src/components/badge.tsx b/packages/ui/src/components/badge.tsx index 82b3a314..7ca60720 100644 --- a/packages/ui/src/components/badge.tsx +++ b/packages/ui/src/components/badge.tsx @@ -3,7 +3,7 @@ import type * as React from 'react'; import { cn } from '../lib/utils'; const badgeVariants = cva( - 'inline-flex items-center gap-1.5 whitespace-nowrap rounded-xs px-2 py-0.5 font-medium text-[0.7rem] transition-all duration-200', + 'inline-flex items-center gap-1.5 whitespace-nowrap rounded-xs px-2 py-0.5 font-medium text-[0.7rem] transition-all duration-200 select-none', { variants: { variant: { diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx index 8d42c3f2..dccdebd6 100644 --- a/packages/ui/src/components/button.tsx +++ b/packages/ui/src/components/button.tsx @@ -6,7 +6,7 @@ import { cn } from '../lib/utils'; import { Tooltip } from './tooltip'; const buttonVariants = cva( - 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm transition-colors duration-200 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 btn-hover-effect', + 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm transition-colors duration-200 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 btn-hover-effect select-none', { variants: { variant: { diff --git a/packages/ui/src/components/checkbox.tsx b/packages/ui/src/components/checkbox.tsx index eba4c14b..c465f667 100644 --- a/packages/ui/src/components/checkbox.tsx +++ b/packages/ui/src/components/checkbox.tsx @@ -12,7 +12,7 @@ const Checkbox = React.forwardRef< >(({ className, ...props }, ref) => ( (({ className, children, ...props }, ref) => ( span]:line-clamp-1', + 'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-ring-3 flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1 select-none', className, )} ref={ref} diff --git a/packages/ui/src/components/slider.tsx b/packages/ui/src/components/slider.tsx index 3282ed22..2d3795a1 100644 --- a/packages/ui/src/components/slider.tsx +++ b/packages/ui/src/components/slider.tsx @@ -47,7 +47,7 @@ function Slider({ {Array.from({ length: _values.length }, (_, index) => ( diff --git a/packages/ui/src/components/switch.tsx b/packages/ui/src/components/switch.tsx index ab969c6c..7f68834a 100644 --- a/packages/ui/src/components/switch.tsx +++ b/packages/ui/src/components/switch.tsx @@ -11,7 +11,7 @@ const Switch = React.forwardRef< >(({ className, ...props }, ref) => ( (({ className, ...props }, ref) => (