JSPM

force-portrait-mode

1.2.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 14
  • Score
    100M100P100Q35355F
  • License MIT

Lightweight library to enforce portrait orientation on mobile devices with customizable animations and messages

Package Exports

  • force-portrait-mode
  • force-portrait-mode/styles/force-portrait.min.css

Readme

force-portrait-mode

npm version Build Status Coverage Status MIT License TypeScript

A lightweight, customizable library that enforces portrait orientation on mobile devices with smooth user experience and professional animations.

✨ Features

  • 🎨 Fully Customizable - Colors, icons, messages, animations, and positioning
  • 📱 Mobile-First - Optimized for all mobile browsers and devices
  • Ultra-Lightweight - < 1KB gzipped, zero dependencies
  • 🔧 Framework Agnostic - Works with React, Vue, Angular, vanilla JS
  • 🎯 TypeScript Ready - Full type definitions included
  • Accessible - Respects user motion preferences and ARIA standards
  • 🌐 CSS-Only Option - Pure CSS solution available (no JavaScript required)
  • 📊 Smart Positioning - Automatic overlap prevention and responsive sizing
  • 🎭 Built-in Themes - Dark, light, neon, and minimal themes included

🚀 Quick Start

Installation

npm install force-portrait-mode
yarn add force-portrait-mode

Basic Usage

import { enablePortraitMode } from 'force-portrait-mode'

// Enable with default settings (40% icon, 70% text positioning)
enablePortraitMode()

// Or with custom options
enablePortraitMode({
  backgroundColor: '#1a1a1a',
  icon: '📲',
  message: 'Please rotate your device to portrait mode',
  theme: 'dark'
})

CSS-Only Usage

<!-- Include the CSS file -->
<link rel="stylesheet" href="node_modules/force-portrait-mode/styles/force-portrait.min.css">

<!-- Or use a CDN -->
<link rel="stylesheet" href="https://unpkg.com/force-portrait-mode@1.2.0/styles/force-portrait.min.css">

📖 Usage Examples

Vanilla JavaScript

import { enablePortraitMode, disablePortraitMode } from 'force-portrait-mode'

// Basic usage
const cleanup = enablePortraitMode({
  backgroundColor: '#000000',
  textColor: '#ffffff',
  icon: '📱',
  message: 'Rotate your phone for better experience'
})

// Clean up when needed
// cleanup()

React Integration

import { enablePortraitMode } from 'force-portrait-mode'
import { useEffect } from 'react'

function App() {
  useEffect(() => {
    const cleanup = enablePortraitMode({
      backgroundColor: '#2d3748',
      textColor: '#e2e8f0',
      icon: '📲',
      theme: 'dark'
    })
    
    return cleanup
  }, [])
  
  return (
    <div className="app">
      <h1>My Mobile App</h1>
      <p>Content optimized for portrait mode</p>
    </div>
  )
}

Vue 3 Integration

<script setup>
import { enablePortraitMode } from 'force-portrait-mode'
import { onMounted, onUnmounted } from 'vue'

let cleanup = null

onMounted(() => {
  cleanup = enablePortraitMode({
    backgroundColor: '#1a1a1a',
    icon: '🎮',
    message: 'Game works best in portrait mode',
    animation: {
      type: 'bounce',
      duration: '1.5s'
    }
  })
})

onUnmounted(() => {
  if (cleanup) cleanup()
})
</script>

<template>
  <div class="game-app">
    <h1>Mobile Game</h1>
    <!-- Your game content -->
  </div>
</template>

TypeScript

import { 
  enablePortraitMode, 
  PortraitModeOptions,
  ThemePreset 
} from 'force-portrait-mode'

const config: PortraitModeOptions = {
  backgroundColor: '#1a1a1a',
  textColor: '#ffffff',
  icon: '📱',
  iconSize: '4rem',
  fontSize: '1.2rem',
  iconPosition: { top: '35%' },
  textPosition: { top: '65%' },
  animation: {
    enabled: true,
    type: 'rotate',
    duration: '2s'
  },
  onShow: () => console.log('Portrait mode activated'),
  onHide: () => console.log('Portrait mode deactivated')
}

const result = enablePortraitMode(config)
console.log('Layout adjusted:', result.layout.adjusted)

🎨 Customization Options

Basic Configuration

enablePortraitMode({
  // Visual customization
  backgroundColor: '#000000',      // Background color
  textColor: '#ffffff',           // Text color  
  icon: '📱',                     // Icon/emoji to display
  iconColor: '#4CAF50',          // Icon color (optional)
  message: 'Custom message',      // Text message
  
  // Typography
  fontFamily: 'Arial, sans-serif',
  fontSize: '1.2rem',             // Responsive: { min: '0.9rem', max: '1.2rem', viewport: '4vw' }
  fontWeight: '600',
  iconSize: '4rem',               // Responsive sizing supported
  
  // Positioning (default: icon 40%, text 70%)
  iconPosition: { top: '40%', left: '50%' },
  textPosition: { top: '70%', left: '50%' },
  
  // Animation
  animation: {
    enabled: true,
    type: 'rotate',               // 'rotate', 'bounce', 'pulse', 'shake'
    duration: '2s',
    rotationAngle: 15
  }
})

Advanced Configuration

enablePortraitMode({
  // Layout control
  layout: {
    preventOverlap: true,         // Automatic overlap prevention
    responsive: true,             // Responsive sizing
    minSpacing: '2rem',          // Minimum space between elements
    fallbackLayout: 'vertical-stack'
  },
  
  // Text handling
  textHandling: {
    maxWidth: '90vw',            // Prevent text overflow
    truncate: true,              // Add ellipsis for long text
    multiLine: false,            // Force single line
    breakWords: false            // Prevent word breaking
  },
  
  // Behavior
  zIndex: 9999,                  // CSS z-index
  overlay: true,                 // Show background overlay
  blur: false,                   // Backdrop blur effect
  hideScrollbar: true,           // Hide scrollbars in landscape
  preventScroll: true,           // Prevent scrolling
  
  // Accessibility
  ariaLabel: 'Rotate device',    // Screen reader label
  respectPrefers: true,          // Respect prefers-reduced-motion
  
  // Callbacks
  onShow: () => console.log('Landscape detected'),
  onHide: () => console.log('Portrait restored')
})

🎭 Built-in Themes

Using Preset Themes

// Dark theme (default)
enablePortraitMode({ theme: 'dark' })

// Light theme
enablePortraitMode({ theme: 'light' })

// Neon theme
enablePortraitMode({ theme: 'neon' })

// Minimal theme
enablePortraitMode({ theme: 'minimal' })

Custom Themes

// Custom theme object
enablePortraitMode({
  theme: {
    backgroundColor: '#ff6b6b',
    textColor: 'white',
    icon: '⚡',
    iconColor: '#ffd93d',
    animation: 'bounce'
  }
})

CSS-Only Themes

/* Apply theme class to body */
body.force-portrait-theme-neon {
  --portrait-bg-color: rgba(0, 0, 0, 0.9);
  --portrait-text-color: #00ff88;
  --portrait-icon-color: #ff0080;
  --portrait-icon: '📲';
}

🔧 API Reference

Functions

enablePortraitMode(options?)

Enables portrait mode enforcement with optional configuration.

Parameters:

  • options (optional): PortraitModeOptions - Configuration object

Returns:

  • PortraitModeResult - Object with cleanup function and layout info

disablePortraitMode()

Disables portrait mode enforcement and cleans up resources.

updatePortraitMode(options)

Updates current portrait mode configuration dynamically.

getPortraitModeState()

Returns current state information.

CSS-Only Usage

Include the CSS file and optionally customize with CSS custom properties:

:root {
  --portrait-bg-color: rgba(0, 0, 0, 0.9);
  --portrait-text-color: #ffffff;
  --portrait-icon: '📱';
  --portrait-message: 'Please rotate your device';
  --portrait-icon-top: 40%;      /* Icon position */
  --portrait-text-top: 70%;      /* Text position */
}

🌍 Browser Compatibility

  • iOS Safari - Full support
  • Android Chrome - Full support
  • Android Firefox - Full support
  • WebView containers (Telegram WebApp, etc.)
  • Progressive Web Apps (PWA)
  • All modern mobile browsers

📱 Framework Integration

Installation

npm install force-portrait-mode

The library provides a framework-agnostic core that works with any JavaScript framework. Simply import the core functions and integrate them into your framework's lifecycle methods as shown in the examples above.

🎯 Default Positioning

The library uses optimized default positioning for mobile devices:

  • Icon: 40% from top (optimal visibility)
  • Text: 70% from top (comfortable reading position)
  • Automatic adjustment for small screens to prevent overlap

⚡ Performance

  • Ultra-Lightweight: < 1KB gzipped (21KB core)
  • Zero dependencies: No external libraries required
  • Optimized build: Tree-shaken with aggressive compression
  • CSS-only option: Pure CSS solution available
  • GPU accelerated: Smooth animations using transform
  • Memory efficient: Automatic cleanup and resource management

🔒 Security

  • No external dependencies
  • No data collection or analytics
  • No network requests
  • CSP (Content Security Policy) friendly
  • Open source and auditable

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/sai-na/force-portrait-mode.git
cd force-portrait-mode
npm install
npm run dev

Running Tests

npm test              # Run tests
npm run test:watch    # Watch mode
npm run test:coverage # With coverage

📄 License

MIT © SAI NATH



Made with ❤️ for mobile-first web development