Skip to content

feat: system-selectable plain text surface (SelectableText) for three platforms - #96

Merged
bytemain merged 1 commit into
staging2from
bisheng/task69-selectable-plain-text
Jul 31, 2026
Merged

feat: system-selectable plain text surface (SelectableText) for three platforms#96
bytemain merged 1 commit into
staging2from
bisheng/task69-selectable-plain-text

Conversation

@bytemain

Copy link
Copy Markdown
Member

Summary

Adds SelectableText — a read-only plain text surface rendered by each platform's native system text view, so the OS supplies the complete selection experience: word selection, drag handles, Select all, Copy, and system extension actions (Translate / Look Up / Share / PROCESS_TEXT) anchored to the selection. The surface never opens an IME; text mutates only through the text prop.

Phase 1 of the thread-message text-selection restoration (Raft #Kuiklybase task #69, source #proj-chat task Tencent-TDS#924). Mobile Phase 2 will consume this to replace the SelectionContainer + custom top-bar action fallback that lost the system menu.

Design

  • core: SelectableTextView (KRSelectableTextView bridge type) measured via the shared rich-text TextShadow — same self-sizing approach as TextAreaView, so layout and native rendering consume identical TextConst wire props (text/fontSize/fontWeight/color/lineHeight/textAlign/useDpFontSizeDim). DSL: ViewContainer.SelectableText {}.
  • Android: TextView + setTextIsSelectable(true) → system ActionMode; not an EditText, so no input connection/IME by construction. reusable=false so selection state never leaks across reuse.
  • iOS: UITextView with editable=NO / selectable=YES / scrollEnabled=NO, zeroed insets; resolved by class-name convention, props via css_ setters; system edit menu.
  • OHOS: ARKUI_NODE_TEXT + NODE_TEXT_COPY_OPTION = LOCAL_DEVICE → native selection/copy menu; registered in ComponentsRegisterEntry; ReuseEnable=false.
  • Compose: SelectableText(text, modifier, style) with an internal pure TextStyle→props resolver.
  • Scrolling is intentionally not built in (wrap in a scroller for long content), keeping three-platform behavior uniform.

Tests

  • KRSelectableTextViewTest (Robolectric): selectable + read-only by construction (onCheckIsTextEditor()==false), text/color/textAlign prop behavior, wire-key contract pin.
  • SelectableTextStylePropsTest (commonTest): color formatting, density scaling, fontWeight bucketing, textAlign keyword mapping, unspecified-omission.
  • iOS/OHOS compile gates via existing CI jobs (renderer warnings-as-errors, ohos-native cross-compile).

Boundary

Source + CI only; three-platform device validation belongs to task Tencent-TDS#924 Phase 2 per the task contract.

Raft: #Kuiklybase task #69

Signed-off-by: BiSheng raft-mobile-bisheng@mail.build

@bytemain
bytemain force-pushed the bisheng/task69-selectable-plain-text branch 3 times, most recently from 01140f5 to 018de72 Compare July 31, 2026 05:51
Add SelectableText, a read-only plain text component rendered by each
platform's native text view so the OS selection experience is available
anchored to the selection. Baseline guarantee: word selection, drag
handles, Select all, Copy; further menu actions (Translate / Look Up /
Share / Android PROCESS_TEXT targets) appear only as provided by the OS
version, locale and installed services. The surface never opens an IME
and text mutates only via the text prop.

- core: SelectableTextView (KRSelectableTextView type) measured with the
  shared rich-text shadow, SelectableTextAttr reusing TextConst wire keys,
  ViewContainer.SelectableText DSL
- Android: KRSelectableTextView (TextView + setTextIsSelectable), system
  ActionMode; registered in KuiklyRenderViewBaseDelegator
- iOS: KRSelectableTextView (UITextView editable=NO selectable=YES),
  system edit menu; resolved by class-name convention
- OHOS: KRSelectableTextView (ARKUI_NODE_TEXT + NODE_TEXT_COPY_OPTION
  local-device copy scope), native selection menu; registered in
  ComponentsRegisterEntry
- Compose: SelectableText(text, modifier, style) with a pure
  style-to-props resolver; every supported field always resolves to a
  concrete wire value (deterministic defaults for unspecified fields) so
  style updates on the reusable node reset prior values on both the
  native renderer and the measuring shadow
- tests: Robolectric behavior contract (selectable/read-only/wire props)
  and commonTest teeth covering resolver defaults, density scaling,
  weight/align mapping, full wire coverage and the
  specified->Default reset sequence
- docs: docs/API/components/selectable-text.md with explicit capability
  boundary (baseline Select all/Copy; extras are platform-provided)

Raft: #Kuiklybase task #69 (Phase 1 of #proj-chat task Tencent-TDS#924)

Signed-off-by: BiSheng <raft-mobile-bisheng@mail.build>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bytemain
bytemain force-pushed the bisheng/task69-selectable-plain-text branch from 018de72 to 1852436 Compare July 31, 2026 06:03
@bytemain
bytemain merged commit d794187 into staging2 Jul 31, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant