UniTextEditable
Editing capability for UniTextSelectable: text storage (gap buffer), undo/redo, IME composition, validators, caret rendering, input intents, touch gesture pipeline, keyboard / clipboard handling, and the public mutation API (InsertText, Cut/Copy/Paste, Undo/Redo, etc.).
Remarks
ContentSizeFitter or place it under a layout group to size its RectTransform from the text; sizing is measured through the UniTextBase component's own ILayoutElement implementation. A pointer click activates it and places the caret; Unity UI navigation reaches it through the hidden UniTextFocusable the editor manages automatically. Put it directly under a RectMask2D to make that parent the clipping viewport and enable internal scrolling when content overflows.public OrderedEvent<InputEdit> InputFilter{ get }Hook: veto or rewrite any document mutation before it applies — typing, paste, IME commit, deletions, cut, transpose. Not consulted for in-progress IME composition, undo/redo replay, or programmatic Text writes. Hooks run by ascending order, each seeing the previous one's result; equal orders retain subscription order and Rejected is sticky. Behaviors subscribe in their OnEnable.
public OrderedEvent<KeyResolve> KeyResolver{ get }Ordered hook for contributing a key-to-action binding before the platform key map. Lower orders resolve first; after one sets an action, later hooks must preserve it.
public OrderedEvent<KeyboardRequest> KeyboardResolver{ get }Ordered hook for composing keyboard configuration each time the soft keyboard is shown. Lower orders contribute first; equal orders retain subscription order.
public LengthLimit LengthLimit{ get; set }Length cap published by the enforcing behavior (LengthLimitBehavior) for counters to display; Max 0 = none. Read-only for consumers — enforcement and configuration live on the behavior, and it republishes on every edit, so an external write here would neither cap input nor survive.
public UniTextSelectable Selectable{ get }Sibling selection component on the same GameObject. Resolved once via GetComponent<T>; RequireComponent guarantees presence.
public TextSelection Selection{ get }Current caret or selection range.
public UniTextBase TextComponent{ get }Text component whose document this editor mutates.
Whether a repeated outward arrow at a formatting boundary clears an explicitly retained typing context. Off unless published by TextFormattingBehavior.
public MarkupVisibility MarkupVisibility{ get; set }How this field presents its markup tags — hidden and atomic (default), revealed around the caret, or shown as raw source. Replaces the former AutoConvert flag.
public List<ChromeRule> MarkupChrome{ get }Rules styling the markup tag characters wherever they are visible — every tag under Raw, the caret's tags under RevealActiveRange. Each rule's Selector picks which markup it targets; rules of different modifier kinds compose, same-kind rules resolve by specificity. Call RefreshMarkup after mutating at runtime.
public IReadOnlyList<BaseModifier> ModifiersAtCaret{ get }Modifiers currently covering the caret / selection. Reused list — copy to keep.
public static UniTextEditable ActiveEditor{ get }Currently active editor across the application — THE "current editor" authority. Selection UI (ISelectionHandles / IInsertionHandle, IMagnifier, ITextContextMenu) pulls geometry and document state from here at call time — implementations are never bound to a specific field, so they can never render against a stale one. Set on Activate, cleared when Deactivate completes.
public PlainTextPastePolicy PlainTextPaste{ get; set }How plain-text paste is interpreted: Literal inserts it verbatim, Parse reparses it as this field's markup, Auto (default) picks by MarkupVisibility.
public TypingMarkupPolicy TypingMarkup{ get; set }Whether hand-typed markup is parsed or kept literal — see TypingMarkupPolicy. Default Parse.
public ValidationState Validation{ get }Current content-validity state — written by validators (via AutoValidateBehavior) or app code through SetValidation, read by field decorators.
Invoked by a virtualised list host (Android RecyclerView, iOS UITableView, Unity scroll-pool, custom) when this editor's GameObject is recycled into a new cell position. Re-arms input lazily on the next focus. The owning component is expected to call RestoreState first when state needs to be preserved across reuse.
public Vector2 GetCaretScreenPosition()Screen-space caret position for codepointIndex (document space) — bottom picks the caret rect's bottom or top edge. The geometry query selection-UI implementations (ISelectionHandles, IMagnifier, system toolbars) issue against ActiveEditor to place themselves.
public void InsertText(ReadOnlySpan<char> text)Inserts text at the current caret position, replacing any active selection. Applies the configured input-filter chain and records the accepted edit for undo.
Copies the selected text to the system clipboard. Does nothing if there is no selection or if the field is in password mode. Walks every built-in clipboard adapter and writes the resulting items as one atomic multi-format clipboard transaction (plain text + custom UniText format + optional HTML / Markdown), so the consumer's paste picks the richest format it understands. When the selection's markup is visible to the user — Raw, or a revealed range under RevealActiveRange — the copy carries only that visible text as plain text and no semantic channels: what is on screen is what pastes.
Pastes text from the system clipboard at the current caret position, replacing any active selection. Probes the built-in clipboard adapters by Priority descending — a cheap HasFormat availability check, then one payload transfer, then deserialize; the first success wins, so only one format ever crosses the clipboard. UniText source (lossless custom format) wins over HTML / Markdown, which win over plain text. The adapter resolves the payload to visible text and destination formatting spans, then inserts both in one document transaction. A format transfers only when the field has a style that renders it; unmatched formatting degrades to plain text. Plain text inserts verbatim.
public Task PasteAsync()Async variant of Paste. Required on WebGL for programmatic paste (toolbar icon, context menu, autofill). This is the batched collect-all read: every requested format arrives in ONE underlying clipboard access via GetItemsAsync (WebGL's single-user-activation rule allows exactly one read); must be awaited from a user-activation context on WebGL. A provider without the async seam degrades to the sync Paste probe. Runs the same pipeline, including the MediaReceived hook.
public Task PastePlainAsync()Async variant of PastePlain — the WebGL-safe paste-without-formatting command. Same activation-context contract as PasteAsync.
Pastes pre-extracted clipboard items through the adapter pipeline, bypassing Provider. Used by iOS UIPasteControl and drag-drop drop sites to avoid a second pasteboard read (which on iOS would surface the system permission prompt). A format transfers only when the field has a style that renders it.
Sets the validation state and fires ValidationChanged. The editor only holds the state; what to validate and when lives in an AutoValidateBehavior or app code (set Pending while an async check runs, then the result).
Hook: consume media — a paste, a drag-and-drop, or a picker selection — before the text-adapter pipeline. Behaviors subscribe in their OnEnable; see MediaInputBehavior.
public Action TextChangedOccurs when document text or attributed ranges change. Read the navigable view without allocation through CharCount, CopyTextTo, and TextEquals; read serialized markup through Text.
public Action<string> ValueChangedOccurs when document text or attributed ranges change. Provides the full serialized source string and allocates only when subscribed.
public Action<string> DocumentChangedOccurs when the text content has changed, alongside TextChanged, with the originating TextChangeReason string — distinguishes user typing (input.type) from paste (input.paste), programmatic mutation (program.set), IME commit (input.type.compose), and undo/redo replay (input.restore). Everything under input.* is user-originated.
public Action<string> SubmittedOccurs when the user has submitted. Enter inserts a newline by default — a submit-resolving behavior defines what submits: SingleLineBehavior (Enter, form field) or SubmitKeyBehavior (Enter or Ctrl/Cmd+Enter, composer). Gamepad submit (EventSystem) also fires this. Carries the current text snapshot. Post-submit focus is the submit-defining behavior's policy — both carry KeepFocusOnSubmit with archetype defaults: SingleLineBehavior releases focus (form), SubmitKeyBehavior keeps it (composer); without one, focus stays.
public Action CancelledOccurs when the user has cancelled editing — Escape (desktop), system back (mobile). The editor does not deactivate automatically; add DefocusOnCancelBehavior or subscribe directly when cancellation should release focus. Android delivers the back key only where the platform routes it to the app: an app opted into OnBackInvokedCallback dispatch (Unity's Predictive Back Support), and Android 13/14 while the keyboard is showing, dismiss the keyboard without raising this.
public Action FocusedOccurs when the editor has gained input focus (activated) — by pointer, navigation, or programmatic select.
public Action<EditingEndReason> DefocusedOccurs when the editor has lost input focus (deactivated), carrying how the session concluded. Submitted and Cancelled report the user's intent while editing continues; this reports the end itself.
public Action<int,int> SelectionChangedFrame-coalesced selection-change notification. Parameters: (selectionStart, selectionEnd) in codepoint indices. Fires at most once per frame after SelectionChanged mutations have settled.
public Action<bool> CompositionStateChangedOccurs when IME composition state changes — fires on start, on commit or cancel.
public Action<CaretContext> CaretContextChangedOccurs (frame-coalesced) when the set of modifiers covering the caret / selection has changed — on caret movement, selection change, or reflow — and when a pending typing style flips (re-query IsStyleActive<T>). Subscribe from an InputBehavior or see CaretContextBehavior for the inspector-wired form.
public Action<ValidationState> ValidationChangedOccurs when Validation has changed.
