// iOS.jsx — Simplified iOS 26 (Liquid Glass) device frame // Based on the iOS 26 UI Kit + Figma status bar spec. No assets, no deps. // Exports: IOSDevice, IOSStatusBar, IOSNavBar, IOSGlassPill, IOSList, IOSListRow, IOSKeyboard // ───────────────────────────────────────────────────────────── // Status bar // ───────────────────────────────────────────────────────────── function IOSStatusBar({ dark = false, time = '9:41' }) { const c = dark ? '#fff' : '#000'; return (
{time}
); } // ───────────────────────────────────────────────────────────── // Liquid glass pill — blur + tint + shine // ───────────────────────────────────────────────────────────── function IOSGlassPill({ children, dark = false, style = {} }) { return (
{/* blur + tint */}
{/* shine */}
{children}
); } // ───────────────────────────────────────────────────────────── // Navigation bar — glass pills + large title // ───────────────────────────────────────────────────────────── function IOSNavBar({ title = 'Title', dark = false, trailingIcon = true }) { const muted = dark ? 'rgba(255,255,255,0.6)' : '#404040'; const text = dark ? '#fff' : '#000'; const pillIcon = (content) => (
{content}
); return (
{/* back chevron */} {pillIcon( )} {/* trailing ellipsis */} {trailingIcon && pillIcon( )}
{/* large title */}
{title}
); } // ───────────────────────────────────────────────────────────── // Grouped list (inset card, r:26) + row (52px) // ───────────────────────────────────────────────────────────── function IOSListRow({ title, detail, icon, chevron = true, isLast = false, dark = false }) { const text = dark ? '#fff' : '#000'; const sec = dark ? 'rgba(235,235,245,0.6)' : 'rgba(60,60,67,0.6)'; const ter = dark ? 'rgba(235,235,245,0.3)' : 'rgba(60,60,67,0.3)'; const sep = dark ? 'rgba(84,84,88,0.65)' : 'rgba(60,60,67,0.12)'; return (
{icon && (
)}
{title}
{detail && {detail}} {chevron && ( )} {!isLast && (
)}
); } function IOSList({ header, children, dark = false }) { const hc = dark ? 'rgba(235,235,245,0.6)' : 'rgba(60,60,67,0.6)'; const bg = dark ? '#1C1C1E' : '#fff'; return (
{header && (
{header}
)}
{children}
); } // ───────────────────────────────────────────────────────────── // Device frame // ───────────────────────────────────────────────────────────── function IOSDevice({ children, width = 402, height = 874, dark = false, title, keyboard = false, }) { return (
{/* dynamic island */}
{/* status bar (absolute) */}
{/* nav + content */}
{title !== undefined && }
{children}
{keyboard && }
{/* home indicator — always on top */}
); } // ───────────────────────────────────────────────────────────── // Keyboard — iOS 26 liquid glass // ───────────────────────────────────────────────────────────── function IOSKeyboard({ dark = false }) { const glyph = dark ? 'rgba(255,255,255,0.7)' : '#595959'; const sugg = dark ? 'rgba(255,255,255,0.6)' : '#333'; const keyBg = dark ? 'rgba(255,255,255,0.22)' : 'rgba(255,255,255,0.85)'; // special-key icons const icons = { shift: , del: , ret: , }; const key = (content, { w, flex, ret, fs = 25, k } = {}) => (
{content}
); const row = (keys, pad = 0) => (
{keys.map(l => key(l, { flex: true, k: l }))}
); return (
{/* liquid glass bg — same recipe as nav pills */}
{/* autocorrect bar */}
{['"The"', 'the', 'to'].map((w, i) => ( {i > 0 &&
}
{w}
))}
{/* key layout */}
{row(['q','w','e','r','t','y','u','i','o','p'])} {row(['a','s','d','f','g','h','j','k','l'], 20)}
{key(icons.shift, { w: 45, k: 'shift' })}
{['z','x','c','v','b','n','m'].map(l => key(l, { flex: true, k: l }))}
{key(icons.del, { w: 45, k: 'del' })}
{key('ABC', { w: 92.25, fs: 18, k: 'abc' })} {key('', { flex: true, k: 'space' })} {key(icons.ret, { w: 92.25, ret: true, k: 'ret' })}
{/* bottom spacer (emoji+mic area, icons omitted) */}
); } Object.assign(window, { IOSDevice, IOSStatusBar, IOSNavBar, IOSGlassPill, IOSList, IOSListRow, IOSKeyboard, });