@radioart/safeareapunk
v0.1.0
Published
Find iPhone home-indicator coverage in your codebase. Scans HTML / JSX / TSX / Vue / Svelte for position:fixed bottom:0 containers missing padding-bottom: env(safe-area-inset-bottom).
Maintainers
Readme
@radioart/keyboardpunk
Find iOS keyboard input traps in your codebase before your users hit them.
A free CLI that scans HTML, JSX, TSX, Vue, Svelte, and Astro files for the most common AI-chat-app mobile bug: a position: fixed container pinned to bottom: 0 with a focusable input inside it. iOS Safari hides the input behind the soft keyboard when the user taps to type.
Apple has not fixed this in 11 iOS major releases. Every chat app shipped this month inherits it.
Usage
npx @radioart/keyboardpunk ./srcThat's it. No install, no signup, no telemetry. Walks your code, prints findings, exits non-zero if any traps are found (so it works as a CI gate).
Common flags
keyboardpunk ./src # default human-readable report
keyboardpunk ./src --format=json # machine-readable JSON
keyboardpunk ./src --format=github # GitHub Actions ::error annotations
keyboardpunk ./src --fix # apply patches in place (requires license key)Exit codes
0— no bugs found1— bugs found (use this as a CI gate)2— scanner crashed (file a bug at https://github.com/radio-art/keyboardpunk/issues)
What it finds
Every container that combines:
position: fixedorposition: stickybottom: 0(or pinned to the bottom)- A focusable input descendant (
textarea,input,select,[contenteditable]) - Without a
visualViewport-aware bottom offset
For each finding, the report prints:
- The file path and line number
- The offending selector (or inline-style element descriptor)
- The exact CSS swap to make (
bottom: var(--keyboard-inset, 0)) - The one-time JavaScript bootstrap that keeps
--keyboard-insetlive
The fix (one CSS line + one JS snippet)
.your-input-bar {
bottom: var(--keyboard-inset, 0);
}(function () {
if (typeof window === 'undefined' || !window.visualViewport) return;
const vv = window.visualViewport;
function update() {
const inset = Math.max(0, window.innerHeight - vv.height - vv.offsetTop);
document.documentElement.style.setProperty('--keyboard-inset', inset + 'px');
}
vv.addEventListener('resize', update);
vv.addEventListener('scroll', update);
update();
})();Browsers that don't support visualViewport (anything pre-iOS 13) ignore the fallback and use the original 0 value. Modern browsers correctly track the soft-keyboard inset.
Free vs paid
| | Free (npx) | $99 lifetime |
|---|---|---|
| Scan an entire repo | ✓ | ✓ |
| Human / JSON / GitHub-format output | ✓ | ✓ |
| CI gate (exit code) | ✓ | ✓ |
| Auto-apply patches with --fix | — | ✓ |
| GitHub Action wrapper | — | ✓ |
| All future updates | ✓ | ✓ |
Buy: https://keyboardpunk.pages.dev#buy
Or get the Punk Pass — all six CSS audit CLIs (KeyboardPunk, StickyPunk, PalettePunk, SelectPunk, AnchorPunk, ScrollPunk) plus every future one — for $299 lifetime.
Privacy
KeyboardPunk runs entirely on your machine. It does not:
- Make any network requests
- Phone home, ever, for any reason
- Collect telemetry
- Validate your license against a remote server (it uses local Ed25519 signature verification)
Source: https://github.com/radio-art/keyboardpunk
This is part of the Light Pact — a 22-principle constitution for tools that respect their users.
Made by
Radio Art LLC · [email protected]
