Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- `@devicekit/frame`: hiding status-bar text no longer hides a phone's physical cutout; Dynamic Island and notch devices retain the screen obstruction outside embedded and landscape frames.
- `@devicekit/devices` and `@devicekit/frame`: Home-button iPhones now describe their asymmetric chassis and physical button, so square LCDs sit inside thick top and bottom bezels instead of reaching the rounded body corners.

## [0.2.2] - 2026-09-04

### Fixed
Expand Down
4 changes: 3 additions & 1 deletion packages/devices/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ const version = systemVersion(profile)
| `SafeAreaRect` | `{ top, left, right, bottom, width, height }` |
| `CutoutShape` | `'notch' \| 'pill' \| 'circle'` |
| `CutoutSpec` | Cutout shape and geometry |
| `DeviceShell` | Screen radius, bezel, and optional body radius |
| `DeviceShell` | Screen radius and uniform `bezel`; `bezelInsets` can override individual edges, `homeButton` describes physical hardware, and per-edge profiles should set `bodyRadius` explicitly |
| `HomeButtonSpec` | `{ diameter }`, the physical Home button centered in the body bezel |
| `ResolvedDeviceShell` | A shell with every edge resolved and `homeButton` set to a spec or `null` |
| `WindowSizeOptions` | Options for `resolveWindowSize()` |
| `DeviceName` | Union of the values in `DEVICE_NAMES` |

Expand Down
4 changes: 3 additions & 1 deletion packages/devices/README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ import { deviceUserAgent, systemVersion } from '@devicekit/devices'
| `SafeAreaRect` | `{ top, left, right, bottom, width, height }`,边是屏幕坐标,跟 `wx.getWindowInfo().safeArea` 一回事 |
| `CutoutShape` | `'notch' \| 'pill' \| 'circle'` |
| `CutoutSpec` | 挖孔的形状和几何:`shape`、`width`、`height`、`top`,可选 `centerX` |
| `DeviceShell` | 机身:`screenRadius`、`bezel`,可选 `bodyRadius` |
| `DeviceShell` | 机身:`screenRadius`、统一的 `bezel`;`bezelInsets` 可单独指定四边,`homeButton` 描述实体 Home 键;用了分边 inset 时应显式设置 `bodyRadius` |
| `HomeButtonSpec` | `{ diameter }`,机身 bezel 中央的实体 Home 键 |
| `ResolvedDeviceShell` | 四边都已补齐、`homeButton` 为规格或 `null` 的机身数据 |
| `WindowSizeOptions` | `resolveWindowSize` 的选项:`orientation`、`navigationBar`、`tabBarHeight` |
| `DeviceName` | 所有 `DEVICE_NAMES` 值的联合类型——也就是每一个真实的 `DeviceProfile.name` |

Expand Down
2 changes: 1 addition & 1 deletion packages/devices/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"scripts": {
"build": "tsc -p tsconfig.build.json",
"generate:device-names": "pnpm run build && node scripts/generate-device-names.mjs",
"check-types": "tsc --noEmit",
"check-types": "tsc --noEmit && tsc --noEmit -p type-tests/tsconfig.json",
"lint": "eslint . --max-warnings 0",
"test": "vitest run --reporter=default --reporter=json --outputFile.json=test-report.json --coverage.enabled --coverage.reporter=json-summary --coverage.reportsDirectory=coverage",
"test:dev": "vitest",
Expand Down
30 changes: 28 additions & 2 deletions packages/devices/src/devices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,23 @@ export interface DeviceShell {
screenRadius: number
/** Body thickness around the screen on every side. 0 = a bezel-less preview. */
bezel: number
/** Body corner radius. Omitted = screenRadius + bezel, which keeps the two concentric. */
/** Per-edge body thickness. Omitted edges keep the uniform `bezel` value. */
bezelInsets?: Partial<EdgeInsets>
/** A physical Home button centered in the bottom bezel. */
homeButton?: HomeButtonSpec | null
/** Body corner radius. Omitted = screenRadius + uniform bezel; profiles with per-edge insets should set this explicitly. */
bodyRadius?: number
}

export interface HomeButtonSpec {
diameter: number
}

export interface ResolvedDeviceShell extends Required<Omit<DeviceShell, 'bezelInsets' | 'homeButton'>> {
bezelInsets: EdgeInsets
homeButton: HomeButtonSpec | null
}

/**
* One device as the table stores it: everything measured, nothing derived.
* Optional fields fall back to that platform's entry in PLATFORM_DEFAULTS —
Expand Down Expand Up @@ -195,7 +208,7 @@ export interface ResolvedDevice {
safeAreaInsets: EdgeInsets
safeAreaInsetsLandscape: EdgeInsets
cutout: CutoutSpec | null
shell: Required<DeviceShell>
shell: ResolvedDeviceShell
}

function withInsets(partial: Partial<EdgeInsets> | undefined, fallback: EdgeInsets): EdgeInsets {
Expand All @@ -222,6 +235,17 @@ export function resolveDevice(profile: DeviceProfile): ResolvedDevice {
const statusBarHeightLandscape = profile.statusBarHeightLandscape ?? defaults.statusBarHeightLandscape
const screenRadius = profile.shell?.screenRadius ?? defaults.shell.screenRadius
const bezel = profile.shell?.bezel ?? defaults.shell.bezel
const uniformBezelInsets = { top: bezel, right: bezel, bottom: bezel, left: bezel }
const profileInsets = profile.shell?.bezelInsets
const bezelInsets = profileInsets !== undefined
? withInsets(profileInsets, uniformBezelInsets)
: profile.shell?.bezel !== undefined
? uniformBezelInsets
: withInsets(defaults.shell.bezelInsets, uniformBezelInsets)
const profileHomeButton = profile.shell?.homeButton
const homeButton = profileHomeButton !== undefined
? profileHomeButton
: defaults.shell.homeButton ?? null

return {
name: profile.name,
Expand All @@ -241,6 +265,8 @@ export function resolveDevice(profile: DeviceProfile): ResolvedDevice {
shell: {
screenRadius,
bezel,
bezelInsets,
homeButton,
bodyRadius: profile.shell?.bodyRadius ?? screenRadius + bezel,
},
}
Expand Down
2 changes: 2 additions & 0 deletions packages/devices/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ export {
type DeviceProfile,
type DeviceShell,
type EdgeInsets,
type HomeButtonSpec,
type Orientation,
type ResolvedDevice,
type ResolvedDeviceShell,
type ScreenSize,
} from './devices.js'

Expand Down
28 changes: 15 additions & 13 deletions packages/devices/src/presets/ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
*/
import type { DeviceProfile } from '../devices.js'

const LEGACY_IPHONE_SHELL = { screenRadius: 0, bodyRadius: 38, bezelInsets: { top: 44, bottom: 48 }, homeButton: { diameter: 30 } }

/** iPhones and iPads. Part of DEVICES; listed here so a host can offer one platform alone. */
export const IOS_DEVICES: readonly DeviceProfile[] = [
{ name: 'iPhone SE', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 15.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone SE', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 15.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone XR', os: 'ios', screen: { width: 414, height: 896 }, pixelRatio: 2, system: 'iOS 18.5', statusBarHeight: 48, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 48, bottom: 34 }, safeAreaInsetsLandscape: { left: 48, right: 48, bottom: 21 }, cutout: { shape: 'notch', width: 231, height: 33, top: 0 } },
{ name: 'iPhone 12 Pro', os: 'ios', screen: { width: 390, height: 844 }, pixelRatio: 3, system: 'iOS 18.5', statusBarHeight: 47, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 47, bottom: 34 }, safeAreaInsetsLandscape: { left: 47, right: 47, bottom: 21 }, cutout: { shape: 'notch', width: 210, height: 32, top: 0 } },
{ name: 'iPhone 14', os: 'ios', screen: { width: 390, height: 844 }, pixelRatio: 3, system: 'iOS 18.5', statusBarHeight: 47, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 47, bottom: 34 }, safeAreaInsetsLandscape: { left: 47, right: 47, bottom: 21 }, cutout: { shape: 'notch', width: 162, height: 34, top: 0 }, shell: { screenRadius: 47 } },
Expand All @@ -26,9 +28,9 @@ export const IOS_DEVICES: readonly DeviceProfile[] = [
{ name: 'iPhone 16 Pro Max', os: 'ios', screen: { width: 440, height: 956 }, pixelRatio: 3, system: 'iOS 18.5', statusBarHeight: 54, safeAreaInsets: { top: 62, bottom: 34 }, safeAreaInsetsLandscape: { left: 62, right: 62, bottom: 21 }, cutout: { shape: 'pill', width: 125, height: 37, top: 14 }, shell: { screenRadius: 62 } },
{ name: 'iPad Mini', os: 'ios', formFactor: 'tablet', screen: { width: 744, height: 1133 }, pixelRatio: 2, system: 'iOS 18.5', statusBarHeight: 24, statusBarHeightLandscape: 24, safeAreaInsets: { top: 24, bottom: 25 }, safeAreaInsetsLandscape: { top: 24, bottom: 25 }, shell: { screenRadius: 18 } },
{ name: 'iPad Pro 13', os: 'ios', formFactor: 'tablet', screen: { width: 1032, height: 1376 }, pixelRatio: 2, system: 'iPadOS 18.5', statusBarHeight: 24, statusBarHeightLandscape: 24, safeAreaInsets: { top: 24, bottom: 25 }, safeAreaInsetsLandscape: { top: 24, bottom: 25 }, shell: { screenRadius: 18 } },
{ name: 'iPhone 5', os: 'ios', screen: { width: 320, height: 568 }, pixelRatio: 2, system: 'iOS 10.3', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 6/7/8', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 6/7/8 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 5', os: 'ios', screen: { width: 320, height: 568 }, pixelRatio: 2, system: 'iOS 10.3', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 6/7/8', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 6/7/8 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone X', os: 'ios', screen: { width: 375, height: 812 }, pixelRatio: 3, system: 'iOS 16.0', statusBarHeight: 44, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 44, bottom: 34 }, safeAreaInsetsLandscape: { left: 44, right: 44, bottom: 21 }, cutout: { shape: 'notch', width: 209, height: 30, top: 0 }, shell: { screenRadius: 39 } },
{ name: 'iPhone XS Max', os: 'ios', screen: { width: 414, height: 896 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 44, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 44, bottom: 34 }, safeAreaInsetsLandscape: { left: 44, right: 44, bottom: 21 }, cutout: { shape: 'notch', width: 209, height: 30, top: 0 } },
{ name: 'iPhone 12/13 mini', os: 'ios', screen: { width: 375, height: 812 }, pixelRatio: 3, system: 'iOS 15.0', statusBarHeight: 50, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 50, bottom: 34 }, safeAreaInsetsLandscape: { left: 50, right: 50, bottom: 21 }, cutout: { shape: 'notch', width: 192, height: 30, top: 0 } },
Expand All @@ -42,13 +44,13 @@ export const IOS_DEVICES: readonly DeviceProfile[] = [
{ name: 'iPad (gen 7)', os: 'ios', formFactor: 'tablet', screen: { width: 810, height: 1080 }, pixelRatio: 2, system: 'iOS 12.2', statusBarHeight: 20, statusBarHeightLandscape: 20, safeAreaInsets: { top: 20 }, safeAreaInsetsLandscape: { top: 20 }, shell: { screenRadius: 0 } },
{ name: 'iPad (gen 11)', os: 'ios', formFactor: 'tablet', screen: { width: 820, height: 1180 }, pixelRatio: 2, system: 'iOS 18.5', statusBarHeight: 24, statusBarHeightLandscape: 24, safeAreaInsets: { top: 24, bottom: 25 }, safeAreaInsetsLandscape: { top: 24, bottom: 25 }, shell: { screenRadius: 18 } },
{ name: 'iPad Pro 11', os: 'ios', formFactor: 'tablet', screen: { width: 834, height: 1194 }, pixelRatio: 2, system: 'iOS 12.2', statusBarHeight: 24, statusBarHeightLandscape: 24, safeAreaInsets: { top: 24, bottom: 25 }, safeAreaInsetsLandscape: { top: 24, bottom: 25 }, shell: { screenRadius: 18 } },
{ name: 'iPhone 6', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 6 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 7', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 7 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 8', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 8 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone SE (3rd gen)', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 18.5', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 6', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 6 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 7', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 7 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 8', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 8 Plus', os: 'ios', screen: { width: 414, height: 736 }, pixelRatio: 3, system: 'iOS 11.0', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 44, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone SE (3rd gen)', os: 'ios', screen: { width: 375, height: 667 }, pixelRatio: 2, system: 'iOS 18.5', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 11', os: 'ios', screen: { width: 414, height: 896 }, pixelRatio: 2, system: 'iOS 12.2', statusBarHeight: 48, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 48, bottom: 34 }, safeAreaInsetsLandscape: { left: 48, right: 48, bottom: 21 }, cutout: { shape: 'notch', width: 231, height: 33, top: 0 } },
{ name: 'iPhone 11 Pro', os: 'ios', screen: { width: 375, height: 812 }, pixelRatio: 3, system: 'iOS 12.2', navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 44, bottom: 34 }, safeAreaInsetsLandscape: { left: 44, right: 44, bottom: 21 }, cutout: { shape: 'notch', width: 209, height: 30, top: 0 } },
{ name: 'iPhone 11 Pro Max', os: 'ios', screen: { width: 414, height: 896 }, pixelRatio: 3, system: 'iOS 12.2', statusBarHeight: 44, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 44, bottom: 34 }, safeAreaInsetsLandscape: { left: 44, right: 44, bottom: 21 }, cutout: { shape: 'notch', width: 209, height: 30, top: 0 } },
Expand All @@ -64,8 +66,8 @@ export const IOS_DEVICES: readonly DeviceProfile[] = [
{ name: 'iPhone 17 Pro', os: 'ios', screen: { width: 402, height: 874 }, pixelRatio: 3, system: 'iOS 26.0', statusBarHeight: 54, safeAreaInsets: { top: 62, bottom: 34 }, safeAreaInsetsLandscape: { top: 0, left: 62, right: 62, bottom: 20 }, cutout: { shape: 'pill', width: 125, height: 37, top: 14 }, shell: { screenRadius: 62 } },
{ name: 'iPhone 17 Pro Max', os: 'ios', screen: { width: 440, height: 956 }, pixelRatio: 3, system: 'iOS 18.7', statusBarHeight: 54, safeAreaInsets: { top: 62, bottom: 34 }, safeAreaInsetsLandscape: { left: 62, right: 62, bottom: 20 }, cutout: { shape: 'pill', width: 125, height: 37, top: 14 } },
{ name: 'iPhone 17e', os: 'ios', screen: { width: 390, height: 844 }, pixelRatio: 3, system: 'iOS 18.7', statusBarHeight: 47, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 47, bottom: 34 }, safeAreaInsetsLandscape: { left: 47, right: 47, bottom: 20 }, cutout: { shape: 'notch', width: 162, height: 34, top: 0 } },
{ name: 'iPhone 4', os: 'ios', screen: { width: 320, height: 480 }, pixelRatio: 2, system: 'iOS 7.1', statusBarHeight: 20, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 5/SE', os: 'ios', screen: { width: 320, height: 568 }, pixelRatio: 2, system: 'iOS 10.3', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: { screenRadius: 0, bodyRadius: 38 } },
{ name: 'iPhone 4', os: 'ios', screen: { width: 320, height: 480 }, pixelRatio: 2, system: 'iOS 7.1', statusBarHeight: 20, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPhone 5/SE', os: 'ios', screen: { width: 320, height: 568 }, pixelRatio: 2, system: 'iOS 10.3', statusBarHeight: 20, navigationBarHeight: 44, navigationBarHeightLandscape: 32, safeAreaInsets: { top: 20 }, shell: LEGACY_IPHONE_SHELL },
{ name: 'iPad Air', os: 'ios', formFactor: 'tablet', screen: { width: 820, height: 1180 }, pixelRatio: 2, system: 'iOS 13.3', statusBarHeight: 24, statusBarHeightLandscape: 24, safeAreaInsets: { top: 24, bottom: 25 }, safeAreaInsetsLandscape: { top: 24, bottom: 25 }, shell: { screenRadius: 18 } },
{ name: 'iPad Pro', os: 'ios', formFactor: 'tablet', screen: { width: 1024, height: 1366 }, pixelRatio: 2, system: 'iOS 11.0', statusBarHeight: 24, statusBarHeightLandscape: 24, safeAreaInsets: { top: 24, bottom: 25 }, safeAreaInsetsLandscape: { top: 24, bottom: 25 }, shell: { screenRadius: 18 } },
{ name: 'iPhone 17 Air', os: 'ios', screen: { width: 420, height: 912 }, pixelRatio: 3, system: 'iOS 18.0', statusBarHeight: 54, safeAreaInsets: { top: 68, bottom: 34 }, safeAreaInsetsLandscape: { left: 68, right: 68, bottom: 20 }, cutout: { shape: 'pill', width: 125, height: 37, top: 20 } },
Expand Down
Loading