Skip to content

SelectionArea

SelectionArea makes static text in one content subtree selectable.

SelectionArea(
Column {
Text("Release notes", TextRole::Title),
Text(release_notes),
Text(build_identifier, TextRole::Label),
}.With(Spacing(8.0F))
)

The shared runtime owns selection ranges, pointer or touch gestures, handles, and the HuxerUI-drawn copy menu. Platform clipboard services perform the final copy operation.

SelectionArea is for static Text content. TextField already owns editable selection and must not rely on a surrounding selection area for its editing behavior.

The selected text remains represented by descendant text semantics rather than a new application state value. Add application-specific semantics to the content only when its visible text does not communicate enough context.

  • Constructor: explicit SelectionArea(View content).
  • Common modifiers: Padding, Frame, Semantics.

See Text and Accessibility.

A normal SelectionArea discovers mounted Text nodes. For a virtual document, supply a std::shared_ptr<const TextSelectionSource> so copying also sees offscreen blocks.

#include <huxerui/huxerui.h>
#include <cstddef>
#include <memory>
#include <optional>
#include <stdexcept>
using namespace huxerui;
class ArticleSnapshot final : public TextSelectionSource {
public:
std::size_t Count() const noexcept override { return 100; }
TextBlockId IdAt(std::size_t index) const override {
if (index >= Count()) {
throw std::out_of_range("Article block index");
}
return index + 1;
}
std::optional<std::size_t> IndexOf(TextBlockId id) const override {
return id >= 1 && id <= Count() ? std::optional<std::size_t>(id - 1) : std::nullopt;
}
TextSelectionBlock BlockAt(std::size_t index) const override {
return {AttributedText("Paragraph " + std::to_string(IdAt(index))), "\n"};
}
};
View Article() {
auto snapshot = std::make_shared<const ArticleSnapshot>();
return SelectionArea(
VirtualList(snapshot->Count(), [snapshot](std::size_t index) {
return Text(snapshot->BlockAt(index).text)
.SelectionBlock(snapshot->IdAt(index))
.Key(snapshot->IdAt(index));
}).ItemExtent(32.0F)
).Source(snapshot)
.With(Frame{.height = 320.0F});
}

The fixed document’s IDs never reorder. Real mutable documents need semantic block IDs preserved across insertions and moves, not current indices. The source is an immutable, synchronous snapshot; publish a replacement when its text changes. Do not read files or start network work from its methods.

Each rendered Text must represent the full block returned by the source. A reconciliation Key and a TextBlockId have different jobs even when the same stable ID is convenient for both. Streaming text demonstrates a larger virtual document.

Source(std::shared_ptr<const TextSelectionSource>) retains an immutable snapshot. Source(nullptr) restores mounted-text discovery. The source’s Count, IdAt, IndexOf, and BlockAt must describe the same ordered document: stable IDs identify blocks, IndexOf maps them back, and BlockAt supplies attributed text plus the separator used when copying between blocks.

Do not let a source read a mutable document that changes beneath these queries. Replace the shared snapshot and render corresponding Text values together. A displayed substring with the full block’s ID creates inconsistent selection geometry; either render the full block or model it as a different logical block.

SelectionArea does not make Canvas-drawn strings or platform text controls part of this document automatically. TextField keeps its own editing selection, and a platform control follows its platform provider. Use explicit semantic descriptions for non-Text visual content rather than assuming a surrounding selection area supplies them.