Skip to content

Commit f40ce1b

Browse files
committed
Add touch support for accepting ghost suggestions
Add touch support for accepting ghost suggestions Changes: - Accept chip: a 44×44 button floating over the field to accept the full hint - Tappable ghost words: tap individual words to accept up to them (word-by-word), same as Ctrl/Cmd+ArrowRight on keyboard - SSR-safe coarse-pointer detection via matchMedia('(pointer: coarse)') - Touch-aware helper text that updates screen-reader announcements - Headless renderTouchAccept prop for custom accept controls - All touch targets accept on pointerdown + preventDefault to keep editor focus New props: - touchAccept?: boolean | 'auto' (default 'auto' = coarse pointers only) - touchAcceptLabel?: string (accessible label, default 'Accept suggestion') - touchAcceptClassName?: string (extra classes for chip) - renderTouchAccept?: (api: TouchAcceptRenderProps) => ReactNode (custom control)
1 parent d23c5e3 commit f40ce1b

7 files changed

Lines changed: 1450 additions & 251 deletions

File tree

‎README.md‎

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ Notes:
296296
| `ArrowUp` | Preview the previous matching hint |
297297
| `Shift+Enter` | Insert a new line |
298298
| `Escape` | Hide the current hint and keep the typed text |
299+
| Tap the accept chip / a ghost word (touch) | Accept the whole hint, or accept up to a word (see [Touch Support](#touch-support)) |
299300
| Click away | Hide the hint and keep the typed text |
300301

301302
## Arrow Navigation
@@ -644,6 +645,53 @@ the suggestion). For `substring` matches that have text *before* the typed
644645
portion, `Ctrl`/`Cmd` + `ArrowRight` falls through to the browser's normal word
645646
navigation.
646647

648+
## Touch Support
649+
650+
Touch devices have no `Tab` key and no `Ctrl`/`Cmd` + `ArrowRight`, so by default
651+
ForeFill shows tappable touch controls whenever a coarse pointer is detected:
652+
653+
- An **accept chip** floating over the field — tap it to accept the whole hint.
654+
- **Tappable ghost words** — tap a gray word to accept up to (and including) it,
655+
the same as pressing `Ctrl`/`Cmd` + `ArrowRight` that many times. Tapping the
656+
last word accepts everything. (Gated by `partialAccept`; start-anchored hints
657+
only — a prefixed `substring` hint accepts in full on tap.)
658+
659+
```tsx
660+
// 'auto' (default) shows the controls only on coarse pointers.
661+
<ForeFill suggestions={suggestions} touchAccept="auto" />
662+
663+
// Force them on (e.g. for a hybrid touch + mouse device), or off.
664+
<ForeFill suggestions={suggestions} touchAccept />
665+
<ForeFill suggestions={suggestions} touchAccept={false} />
666+
```
667+
668+
The controls fire on `pointerdown` and keep focus on the editor, so the soft
669+
keyboard stays up and you can keep typing after accepting. The helper text and
670+
the screen-reader announcement switch to touch wording automatically.
671+
672+
Bring your own control with `renderTouchAccept`. The returned node **must** call
673+
`accept()` from an `onPointerDown` that calls `preventDefault()`, otherwise the
674+
editor blurs and the hint is cleared before the accept runs:
675+
676+
```tsx
677+
<ForeFill
678+
suggestions={suggestions}
679+
touchAccept
680+
renderTouchAccept={({ accept, suggestion, label }) => (
681+
<button
682+
type="button"
683+
aria-label={label}
684+
onPointerDown={(e) => {
685+
e.preventDefault();
686+
accept();
687+
}}
688+
>
689+
↵ {suggestion}
690+
</button>
691+
)}
692+
/>
693+
```
694+
647695
## Disable Inline Fill
648696

649697
Use this when you want the editable surface without ghost hints.
@@ -762,6 +810,8 @@ in your own stylesheet to re-skin the component.
762810
| `--ff-key-radius` | Keycap border radius |
763811
| `--ff-key-font-size` | Keycap text size |
764812
| `--ff-key-font-weight` | Keycap font weight |
813+
| `--ff-touch-accept-size` | Touch accept chip target size (default `34px`; set to `44px` for WCAG 2.5.5) |
814+
| `--ff-touch-accept-glyph-size` | Touch accept chip glyph (↵) text size |
765815
| `--ff-font` | Font family |
766816
| `--ff-padding-y` | Vertical padding |
767817
| `--ff-padding-x` | Horizontal padding |
@@ -811,7 +861,12 @@ Every public prop below includes its use and a short example.
811861
| `onDismiss` | `() => void` | Runs when Escape hides a visible hint. | `<ForeFill onDismiss={() => track('dismissed')} />` |
812862
| `acceptOnEnter` | `boolean`, default `true` | When false, Enter commits typed text and Tab accepts hints. | `<ForeFill acceptOnEnter={false} />` |
813863
| `commitOnBlur` | `boolean`, default `false` | Commits the current value when focus leaves the field. | `<ForeFill commitOnBlur onCommit={save} />` |
814-
| `partialAccept` | `boolean`, default `true` | Lets users accept one word with Ctrl/Cmd + ArrowRight. | `<ForeFill partialAccept={false} />` |
864+
| `partialAccept` | `boolean`, default `true` | Lets users accept one word with Ctrl/Cmd + ArrowRight (and by tapping a ghost word on touch). | `<ForeFill partialAccept={false} />` |
865+
| `touchAccept` | `boolean \| 'auto'`, default `'auto'` | Shows tappable touch controls (accept chip + ghost words). `'auto'` = coarse pointers only; `true`/`false` force on/off. | `<ForeFill touchAccept />` |
866+
| `touchAcceptLabel` | `string`, default `'Accept suggestion'` | Accessible label for the accept chip. | `<ForeFill touchAcceptLabel="Use suggestion" />` |
867+
| `touchAcceptClassName` | `string` | Extra classes merged onto the accept chip. | `<ForeFill touchAcceptClassName="my-chip" />` |
868+
| `renderTouchAccept` | `(api: TouchAcceptRenderProps) => ReactNode` | Render your own accept control; call `accept()` from a `preventDefault`-ed `onPointerDown`. | See [Touch Support](#touch-support) |
869+
| `active` | `boolean`, default `false` | Renders the inline ghost as if focused without stealing DOM focus (avoids opening the soft keyboard on touch). For showcase/preview scenarios with an externally driven value. | `<ForeFill active value={value} suggestions={suggestions} />` |
815870

816871
### Helper, Status, And Accessibility
817872

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "forefill",
33
"private": false,
4-
"version": "0.1.3",
4+
"version": "0.1.4",
55
"description": "ForeFill — inline ghost-text autocomplete for React textareas, textboxes, and contenteditable surfaces.",
66
"type": "module",
77
"license": "MIT",

0 commit comments

Comments
 (0)