- Add vuedraggable for mobile-friendly lineup building - Add touch delay and threshold settings for better mobile UX - Add drag ghost/chosen/dragging visual states - Add replacement mode visual feedback when dragging over occupied slots - Add getBench action to useGameActions for substitution panel - Add BN (bench) to valid positions in LineupPlayerState - Update lineup service to load full lineup (active + bench) - Add touch-manipulation CSS to UI components (ActionButton, ButtonGroup, ToggleSwitch) - Add select-none to prevent text selection during touch interactions - Add mobile touch patterns documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
164 lines
6.3 KiB
Markdown
164 lines
6.3 KiB
Markdown
# Mobile Text Selection Prevention Review
|
|
|
|
**Date**: 2026-01-17
|
|
**Purpose**: Review and apply text selection prevention patterns for mobile touch/drag interactions
|
|
|
|
## Pattern Applied
|
|
|
|
```css
|
|
/* Prevent text selection on all draggable/interactive elements AND their children */
|
|
:deep([draggable="true"]),
|
|
:deep([draggable="true"] *),
|
|
:deep(.sortable-item),
|
|
:deep(.sortable-item *),
|
|
.interactive-item,
|
|
.interactive-item * {
|
|
-webkit-user-select: none !important;
|
|
-moz-user-select: none !important;
|
|
-ms-user-select: none !important;
|
|
user-select: none !important;
|
|
-webkit-touch-callout: none !important; /* Prevent iOS callout menu */
|
|
}
|
|
|
|
/* Touch action on containers only */
|
|
:deep([draggable="true"]),
|
|
:deep(.sortable-item) {
|
|
touch-action: manipulation; /* Allow pan/zoom but optimize for touch */
|
|
}
|
|
```
|
|
|
|
**Tailwind utilities used**: `select-none` and `touch-manipulation`
|
|
|
|
## Components Reviewed
|
|
|
|
### ✅ Already Compliant (No Changes Needed)
|
|
|
|
#### LineupBuilder.vue
|
|
- **Status**: Fully compliant
|
|
- **Reason**: Already has comprehensive text selection prevention for vuedraggable components
|
|
- **Implementation**: Uses `:deep()` selectors with complete iOS support
|
|
- **Details**:
|
|
- Prevents text selection on all draggable roster items
|
|
- Prevents text selection on lineup slot items
|
|
- Applies to all child elements using wildcard selectors
|
|
- Includes iOS-specific `-webkit-touch-callout: none` for callout menu prevention
|
|
- Uses `touch-action: manipulation` for proper touch optimization
|
|
|
|
### ✅ Updated Components
|
|
|
|
#### 1. UI/ToggleSwitch.vue
|
|
- **Changes**:
|
|
- Added `select-none` class to root container
|
|
- Added `<style scoped>` block with text selection prevention for button and all children
|
|
- Added `touch-action: manipulation` to button
|
|
- **Reason**: Toggle switches are frequently tapped on mobile and users were selecting text accidentally
|
|
|
|
#### 2. UI/ButtonGroup.vue
|
|
- **Changes**:
|
|
- Added `select-none` class to root container
|
|
- Added `<style scoped>` block with text selection prevention for all buttons and children
|
|
- Added `touch-action: manipulation` to buttons
|
|
- **Reason**: Button groups used for decisions (infield depth, outfield depth) are touch-intensive
|
|
|
|
#### 3. UI/ActionButton.vue
|
|
- **Changes**:
|
|
- Added `select-none touch-manipulation` Tailwind classes to button element
|
|
- Added `<style scoped>` block with text selection prevention for button and all children
|
|
- **Reason**: Primary action buttons (Submit, Roll Dice, etc.) are core mobile interactions
|
|
|
|
#### 4. Schedule/GameCard.vue
|
|
- **Changes**:
|
|
- Added `select-none touch-manipulation` classes to "Play This Game" button
|
|
- **Reason**: Game card buttons are frequently tapped to start games
|
|
|
|
#### 5. Substitutions/SubstitutionPanel.vue
|
|
- **Changes**:
|
|
- Added `select-none` class to tab navigation container
|
|
- Added `select-none` class to player selection grid
|
|
- Added `touch-manipulation` class to player buttons
|
|
- Updated CSS for `.tab-button` with user-select and touch-action properties
|
|
- Updated CSS for `.player-button` with user-select properties
|
|
- **Reason**: Tab navigation and player selection involve frequent tapping on mobile
|
|
|
|
#### 6. Decisions/OffensiveApproach.vue
|
|
- **Changes**:
|
|
- Added `select-none` class to action selection grid container
|
|
- Added `touch-manipulation` class to action buttons
|
|
- **Reason**: Action selection buttons (Swing Away, Steal, Hit and Run, etc.) are tapped frequently
|
|
|
|
### ⚠️ Components NOT Modified (No Touch/Drag Interactions)
|
|
|
|
#### Display/Read-Only Components
|
|
- **Game/ScoreBoard.vue** - Pure display, no interaction
|
|
- **Game/GameBoard.vue** - Visual diamond display, no dragging
|
|
- **Game/CurrentSituation.vue** - Player card display
|
|
- **Game/PlayByPlay.vue** - Text feed, needs text selection for copying plays
|
|
- **Game/GameStats.vue** - Tabular data display
|
|
|
|
#### Decision Input Components (Already Use UI Components)
|
|
- **Decisions/DecisionPanel.vue** - Container only, uses child components that were updated
|
|
- **Decisions/DefensiveSetup.vue** - Uses ButtonGroup and ToggleSwitch (already updated)
|
|
- **Decisions/StolenBaseInputs.vue** - Uses ToggleSwitch (already updated)
|
|
|
|
#### Gameplay Components
|
|
- **Gameplay/DiceRoller.vue** - Uses ActionButton (already updated)
|
|
- **Gameplay/ManualOutcomeEntry.vue** - Form inputs (needs text selection)
|
|
- **Gameplay/PlayResult.vue** - Display only
|
|
|
|
#### Substitution Components (Use Updated SubstitutionPanel)
|
|
- **Substitutions/PinchHitterSelector.vue** - Uses parent panel's classes
|
|
- **Substitutions/PitchingChangeSelector.vue** - Uses parent panel's classes
|
|
- **Substitutions/DefensiveReplacementSelector.vue** - Uses parent panel's classes
|
|
|
|
## Summary Statistics
|
|
|
|
- **Total Components Reviewed**: 33 Vue files
|
|
- **Components Updated**: 6
|
|
- **Components Already Compliant**: 1 (LineupBuilder.vue)
|
|
- **Components Skipped (Read-Only/Form Inputs)**: 26
|
|
|
|
## Testing Recommendations
|
|
|
|
Test on actual mobile devices:
|
|
1. **iPhone/iPad** (iOS Safari) - Test `-webkit-touch-callout` prevention
|
|
2. **Android** (Chrome Mobile) - Test general touch behavior
|
|
3. **Focus Areas**:
|
|
- Tap buttons rapidly without text selection
|
|
- Drag roster players in LineupBuilder without selecting text
|
|
- Toggle switches in defensive/offensive decisions
|
|
- Tap player cards in substitution panel
|
|
- Select actions in OffensiveApproach
|
|
|
|
## Pattern Rationale
|
|
|
|
### Why `select-none` on Interactive Elements?
|
|
- Mobile users often tap and hold slightly too long, triggering text selection
|
|
- Text selection on buttons/cards creates confusing blue highlight overlays
|
|
- Improves perceived responsiveness of the UI
|
|
|
|
### Why `touch-manipulation`?
|
|
- Optimizes touch events for browser (faster response)
|
|
- Allows pan/zoom gestures but disables double-tap-to-zoom on these elements
|
|
- Better UX for game controls
|
|
|
|
### Why NOT Apply to Everything?
|
|
- **Form inputs** need text selection for editing values
|
|
- **Play-by-play text** users may want to copy/paste plays
|
|
- **Score displays** may be useful to copy scores
|
|
- Only apply where text selection is **purely accidental** and **never intentional**
|
|
|
|
## Future Considerations
|
|
|
|
If new components are added with:
|
|
- Drag-and-drop functionality
|
|
- Touch-based sliders/toggles
|
|
- Clickable cards/buttons
|
|
- Tab navigation
|
|
|
|
Remember to apply this pattern immediately.
|
|
|
|
---
|
|
|
|
**Reviewed By**: Claude (Atlas - Principal Engineer)
|
|
**Review Type**: Mobile UX Enhancement
|
|
**Compliance**: Mobile-First Design Standards |