make native text widgets selection-aware (T-135)
Foundation for rendering the Claude conversation natively (T-132) with the cross-widget select+copy the terminal gives today. Converts the raw RichText in clide_markdown + clide_code_block to Text.rich, which registers with a Flutter SelectionArea's selection machinery (raw RichText does not). Adds a selectionBackground surface token (globalFocus at ~40% alpha, matching the terminal's selection tint) via tokens + resolver default; bundled palettes are untouched (D-69). Text and code blocks now select across each other under a SelectionArea; tables and tappable link-spans remain non-selectable islands for now. The selection contrast pair is intentionally not added to the WCAG gate: the tint is semi-transparent and the gate's neutral-grey compositor would false-fail it (documented in contrast.dart); deferred to the -hc/-cb pass. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -185,6 +185,20 @@ List<ContrastPair> extendedPairs(SurfaceTokens s) => [
|
||||
background: s.globalBackground,
|
||||
largeText: true,
|
||||
),
|
||||
// selection.foreground_on_selection is intentionally omitted here.
|
||||
//
|
||||
// The `selectionBackground` token defaults to `globalFocus.withAlpha(0x66)`
|
||||
// — a semi-transparent tint composited onto the real content background at
|
||||
// runtime. The WCAG compositor in contrastRatio() blends onto neutral grey
|
||||
// (0x808080) rather than the actual dark panel background, which
|
||||
// systematically understates the readable contrast for all current bundled
|
||||
// themes. Adding the pair here would require retuning palettes, which D-69
|
||||
// forbids for user-contract themes.
|
||||
//
|
||||
// Enforcement is deferred to a follow-up ticket: -hc/-cb variants will
|
||||
// declare an explicit `surface.selectionBackground` override that is
|
||||
// opaque enough to clear 3:1 against the grey compositor, at which point
|
||||
// the pair can be added to extendedPairs.
|
||||
];
|
||||
|
||||
/// Convenience for tests: returns the list of [canonicalPairs] that
|
||||
|
||||
@@ -36,6 +36,14 @@ class ThemeResolver {
|
||||
);
|
||||
}
|
||||
|
||||
// selectionBackground defaults to globalFocus at ~40 % opacity (0x66 alpha)
|
||||
// when the theme does not declare an explicit surface override for it.
|
||||
// This matches the terminal's established convention of
|
||||
// `globalFocus.withAlpha(0x66)` for focus-adjacent highlights.
|
||||
if (surfaceOverride?[TokenKeys.selectionBackground] == null) {
|
||||
surface[TokenKeys.selectionBackground] = surface[TokenKeys.globalFocus]!.withAlpha(0x66);
|
||||
}
|
||||
|
||||
final extTokens = <String, Color>{};
|
||||
if (extensionOverride != null) {
|
||||
for (final entry in extensionOverride.entries) {
|
||||
@@ -111,6 +119,7 @@ class ThemeResolver {
|
||||
syntaxComment: surface[TokenKeys.syntaxComment]!,
|
||||
syntaxMethod: surface[TokenKeys.syntaxMethod]!,
|
||||
syntaxPunct: surface[TokenKeys.syntaxPunct]!,
|
||||
selectionBackground: surface[TokenKeys.selectionBackground]!,
|
||||
extensionTokens: extTokens,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ class SurfaceTokens {
|
||||
required this.syntaxComment,
|
||||
required this.syntaxMethod,
|
||||
required this.syntaxPunct,
|
||||
// selection
|
||||
required this.selectionBackground,
|
||||
required this.extensionTokens,
|
||||
});
|
||||
|
||||
@@ -186,6 +188,11 @@ class SurfaceTokens {
|
||||
final Color syntaxMethod;
|
||||
final Color syntaxPunct;
|
||||
|
||||
/// Background color for text selection highlights. Rendered at ~40 % alpha
|
||||
/// (like the terminal's `globalFocus.withAlpha(0x66)`) so the selected text
|
||||
/// remains legible through the tint.
|
||||
final Color selectionBackground;
|
||||
|
||||
/// Extension-declared tokens keyed by their dotted path
|
||||
/// (e.g. `ext.sqlite.table.background`).
|
||||
final Map<String, Color> extensionTokens;
|
||||
@@ -296,6 +303,9 @@ abstract class TokenKeys {
|
||||
static const syntaxMethod = 'syntax.method';
|
||||
static const syntaxPunct = 'syntax.punct';
|
||||
|
||||
// selection
|
||||
static const selectionBackground = 'selection.background';
|
||||
|
||||
static const all = <String>[
|
||||
globalForeground,
|
||||
globalBackground,
|
||||
@@ -363,5 +373,6 @@ abstract class TokenKeys {
|
||||
syntaxComment,
|
||||
syntaxMethod,
|
||||
syntaxPunct,
|
||||
selectionBackground,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user