Conversation
There was a problem hiding this comment.
Pull request overview
Adds an opt-in linkOnPaste prop to EnrichedTextInput across iOS/Android/Web so that pasting a bare URL over a non-empty selection linkifies the selected text instead of replacing it, matching common rich-text editor behavior while keeping default behavior unchanged.
Changes:
- Introduces the
linkOnPasteprop end-to-end (types/defaults, native codegen spec, native + web wrappers). - Implements platform-specific paste interception/linkification logic (iOS/Android/Web) with “whole-string URL” detection and scheme-less
https://normalization. - Updates example apps and adds Playwright E2E coverage for Web.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/web/linkOnPaste.ts | Implements web linkOnPaste paste handler and URL normalization. |
| src/web/EnrichedTextInput.tsx | Wires handleLinkOnPaste into TipTap paste handling and threads prop via refs. |
| src/utils/EnrichedTextInputDefaultProps.ts | Adds linkOnPaste: false default. |
| src/types.ts | Documents and exposes linkOnPaste?: boolean on the public props interface. |
| src/spec/EnrichedTextInputNativeComponent.ts | Adds linkOnPaste?: boolean to codegen native props. |
| src/native/EnrichedTextInput.tsx | Passes linkOnPaste through the native wrapper to the native component. |
| ios/styles/LinkStyle.mm | Adds “match entire string” link-regex helper for bare-URL paste detection. |
| ios/interfaces/StyleHeaders.h | Exposes the new LinkStyle “entire string” matcher in headers. |
| ios/EnrichedTextInputView.mm | Adds tryAddLinkAt... (BOOL return) and linkURLIfEntireString: helper for iOS paste flow. |
| ios/EnrichedTextInputView.h | Exposes linkOnPaste ivar and new helper method declarations. |
| ios/enrichedInputTextView/EnrichedInputTextView.mm | Adds iOS paste: branch for linkifying selection + refactors plain-text extraction helper. |
| docs/INPUT_API_REFERENCE.md | Documents the new linkOnPaste prop behavior and platform support. |
| apps/example/src/screens/TestScreen.tsx | Enables linkOnPaste in the native example screen for manual testing. |
| apps/example/src/screens/DevScreen.tsx | Enables linkOnPaste in the native dev screen for manual testing. |
| apps/example-web/src/testScreens/TestLinks.tsx | Enables linkOnPaste in the web example test screen. |
| apps/example-web/src/App.tsx | Enables linkOnPaste in the main web example app configuration. |
| android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt | Adds ViewManager setter for linkOnPaste. |
| android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt | Implements Android selection-linkify-on-paste logic + whole-string regex companion. |
| .playwright/tests/links.spec.ts | Adds E2E suite covering linkOnPaste success + fallback cases. |
| .playwright/helpers/clipboard.ts | Adds helper to paste over an existing selection without collapsing it. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
c404c81 to
b0a05c2
Compare
When enabled, pasting clipboard content that is solely a URL over a
non-empty selection turns the selected text into a link pointing to that
URL instead of replacing the selection. Disabled by default.
- Recognizes a URL only when it fully matches linkRegex (or the default
link-detection patterns); scheme-less URLs get an https:// prefix.
- Falls back to a normal paste for empty/whitespace selections, non-bare-URL
clipboard text, or when the link style is blocked (inline code, code block).
- No effect when link detection is disabled via linkRegex={null}.
JS: prop on the codegen spec, types, default props, native/web wrappers.
iOS: gated branch in paste:, tryAddLinkAt:/linkURLIfEntireString: on the view,
matchesEntireLinkRegexWithConfig: on LinkStyle.
Android: gated branch in handleTextPaste, linkifySelectionOnPaste helper,
linkExactRegex companion, setLinkOnPaste ViewManager setter.
Web: handleLinkOnPaste wired into TipTap handlePaste.
Docs (INPUT_API_REFERENCE), example apps and a Playwright linkOnPaste suite
(4 cases, all green; full links suite 35 passed).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b0a05c2 to
3770d52
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Address the identified URL matching, fallback paste, href normalization, and whitespace preservation issues.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (2)
android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt:443
- The Android path stores
pasteddirectly as the href, so scheme-less URLs are emitted without the requiredhttps://prefix. Normalize the href before creating the span, while retainingselectedTextas the visible content.
styles.setLinkSpan(freshStart, freshEnd, selectedText, pasted)
ios/EnrichedTextInputView.mm:1571
- Scheme-less URLs are returned unchanged, so the manual link stores
www.example.comas its href instead of the documentedhttps://www.example.com. Normalize the returned URL beforeaddLinkAt:...stores it.
return text;
- Files reviewed: 18/18 changed files
- Comments generated: 5
- Review effort level: Lite
|
I've adjusted a couple things here:
|
Summary
Adds an opt-in
linkOnPasteprop to<EnrichedTextInput />(iOS, Android, Web).When enabled, pasting clipboard content that is solely a URL over a
non-empty selection turns the selected text into a link pointing to that
URL, instead of replacing the selection with the pasted text. This is a common
rich-text convenience (it mirrors the "paste URL onto selected text" behavior
of editors like Google Docs, Notion, Slack).
Disabled by default (
linkOnPaste={false}), so existing behavior isunchanged for current users — the feature only activates when explicitly turned
on.
Behavior details:
configured
linkRegex(or the default link-detection patterns whenlinkRegexis not set). Clipboard text containing a URL plus other text(e.g.
see https://example.com) is not treated as a link and falls backto a normal paste.
www.example.com) get anhttps://prefix in theresulting link href, while the visible selected text is preserved.
or when the link style cannot be applied at the selection (inside inline code
or a code block).
linkRegex={null}.Implementation:
types.ts, default props (false), and thenative/web
EnrichedTextInputwrappers.EnrichedInputTextView'spaste:; a newtryAddLinkAt:...(returns whether the link was applied) andlinkURLIfEntireString:onEnrichedTextInputView; amatchesEntireLinkRegexWithConfig:full-string variant onLinkStyle.handleTextPaste; alinkifySelectionOnPastehelper plus a
linkExactRegex(whole-string) companion tolinkRegex, and asetLinkOnPasteViewManager setter.handleLinkOnPastewired into the TipTap editor'shandlePaste,reusing the existing autolink regex and the
EnrichedLink.setLinkcommand(which already bails out when the link style is blocked).
Test Plan
Web (automated): added a
test-links linkOnPastesuite to.playwright/tests/links.spec.tscovering: linkifying the selection with a fullURL,
https://prefixing for a scheme-less URL, and the two fallback cases(non-bare-URL text, and no selection). Run with
yarn test:e2e:web. The fulllinks suite (35 tests) passes.
Manual (all platforms). The example app enables
linkOnPasteon its editorscreens. To verify:
Hello world, selectworld.linkRegexaccepts and paste over the selection→
worldbecomes a link to that URL (visible text unchanged).www.…) → the link href is prefixed withhttps://.see https://…) → normal paste(selection replaced, not linkified).
linkOnPaste={false}→ step 2 becomes a normal paste again (selectionreplaced), confirming the default/off behavior is unchanged.
yarn typecheck,yarn lint, andyarn lint-clangall pass; the AndroidGradle
lintVerifybuilds the module cleanly.Compatibility
Checklist