diff --git a/apps/storybook/src/Foundations.stories.tsx b/apps/storybook/src/Foundations.stories.tsx index 112c54a..7846cbf 100644 --- a/apps/storybook/src/Foundations.stories.tsx +++ b/apps/storybook/src/Foundations.stories.tsx @@ -708,13 +708,7 @@ function EaseRow({ name }: { name: string }) { // A preset player - clicking Play remounts the sample with the literal `animate-*` class so // the ACTUAL Tailwind utility runs. `animationName` is the preset's label, also used as the // badge text; the remount (key bump) restarts the "out" presets so they visibly animate away. -function PresetPlayer({ - cls, - animationName, -}: { - cls: string; - animationName: string; -}) { +function PresetPlayer({ cls, animationName }: { cls: string; animationName: string }) { const [tick, setTick] = useState(0); return (
@@ -876,7 +870,8 @@ function Motion() { style={{ fontSize: 'var(--text-sm)', color: 'var(--color-text)', - background: 'color-mix(in srgb, var(--color-warning) 12%, var(--color-surface))', + background: + 'color-mix(in srgb, var(--color-warning) 12%, var(--color-surface))', borderLeft: '3px solid var(--color-warning)', borderRadius: 'var(--radius-sm)', padding: '0.5rem 0.75rem', diff --git a/docs/feedback/0017-form-controls-ios-zoom.md b/docs/feedback/0017-form-controls-ios-zoom.md new file mode 100644 index 0000000..8edbc07 --- /dev/null +++ b/docs/feedback/0017-form-controls-ios-zoom.md @@ -0,0 +1,33 @@ +# 0017 - Form controls auto-zoom on iOS + +Source: rogueoak.com subscribe form (rogueoak feedback 0002) - tapping a canopy `Input` on a phone +zoomed the page. The same latent bug is in every canopy consumer, so it is fixed at the source here. + +## Symptom + +On iOS Safari, focusing a canopy `Input`, `Textarea`, or `Select` trigger zoomed the whole page in - +a jarring shift the user then had to undo. Reproduced on rogueoak.com; applies to any consumer with +these controls on a phone. + +## Root cause + +iOS Safari auto-zooms to a focused form control whenever its computed `font-size` is below **16px**. +All three field controls used `text-sm` (14px) in their base class, so every one tripped the zoom. +A platform rule the component defaults did not account for - not a consumer bug, so a per-app +override (what rogueoak shipped first) is the wrong layer. The design system owns the default. + +## Fix + +Set the focusable field controls to `text-base md:text-sm`: **16px on mobile** (no iOS zoom) and +**14px from the `md` breakpoint up** (preserves the denser desktop typography). Applied to `Input`, +`Textarea`, and the `Select` trigger. The `SelectItem` / `SelectLabel` dropdown rows stay `text-sm` - +they are not focusable text fields, so they never zoom. `md` is a width breakpoint, not a touch test, +but that is the right proxy here: iOS auto-zoom is a small-viewport phone behavior, and phones sit +below `md`. Each control gains a test asserting `text-base md:text-sm` (and not bare `text-sm`). + +## Learning + +**Interactive form controls must default to font-size >= 16px on mobile.** A 16px minimum on +focusable fields is a design-system-level guarantee, not a per-app override - fix it once in the +component so every consumer inherits it. Use `text-base md:text-sm` when the desktop design wants a +denser 14px. Verify the computed size, not just the class. diff --git a/docs/overview/learnings.md b/docs/overview/learnings.md index efc8881..6fc1ec4 100644 --- a/docs/overview/learnings.md +++ b/docs/overview/learnings.md @@ -535,3 +535,16 @@ or a mid-flight glitch. For any spring/overshoot demo, size the stage for the ** `travel x max-bezier-y`, add clearance) and prove the extreme is in-bounds by frame-sampling the live animation or freezing at the computed peak. Never ship a motion affordance you have not watched fire (a CSS `:hover` re-declaring an identical `animation-name` restarts nothing). + +## Form controls must default to >=16px on mobile (iOS auto-zoom) + +iOS Safari auto-zooms the page when a focused ``/`