Skip to content

Comments

feat: add SelectableText widget and parser with documentation and exa…#395

Merged
divyanshub024 merged 6 commits intoStacDev:devfrom
xkaper001:issue385
Dec 21, 2025
Merged

feat: add SelectableText widget and parser with documentation and exa…#395
divyanshub024 merged 6 commits intoStacDev:devfrom
xkaper001:issue385

Conversation

@xkaper001
Copy link
Contributor

@xkaper001 xkaper001 commented Dec 15, 2025

Description

  • Adds SelectableText widget support end-to-end (core widget + framework parser).
  • Registers the new widget type and exports it through existing widget registries.
  • Adds docs page for SelectableText and includes it in the docs index.
  • Updates stac_gallery JSON to include a SelectableText example and wires it into the gallery home screen.

Closes #385

Preview

Clipboard-20251215-214405-748.mp4

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Code refactor
  • Build configuration change
  • Documentation
  • Chore

Summary by CodeRabbit

  • New Features

    • Added a SelectableText widget with rich selectable spans, cursor customization, interactive-selection control, tap callbacks, and text scaling.
  • Documentation

    • Added detailed docs with properties, migration note, and JSON usage examples; updated docs navigation.
  • Examples

    • Added gallery entry and example screen demonstrating standard, rich, custom-cursor, and non-interactive selectable text.
  • Chores

    • Added JSON (de)serialization support and unpinned example dependency versions.

✏️ Tip: You can customize this high-level summary in your review settings.

@CLAassistant
Copy link

CLAassistant commented Dec 15, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

Walkthrough

Adds SelectableText support: new serializable core model, generated JSON (de)serialization, parser, parser registration and export, docs and gallery example; removes a few unused parser imports and unpins some example dependency versions.

Changes

Cohort / File(s) Summary
Documentation
docs/docs.json, docs/widgets/selectable_text.mdx
Added navigation entry and new docs page describing the SelectableText widget, its properties (including deprecation note for textScaleFactortextScaler), migration guidance, and a JSON example.
Examples / Gallery
examples/stac_gallery/assets/json/home_screen.json, examples/stac_gallery/assets/json/selectable_text_example.json
Added gallery list tile and a new example JSON demonstrating standard, rich, cursor-customized, and interactive-selection variants.
Core widget model
packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart, packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.g.dart, packages/stac_core/lib/widgets/widgets.dart
New StacSelectableText model with full configuration surface, JsonSerializable annotations, generated (de)serialization helpers, and exported from widgets barrel.
Widget type enum
packages/stac_core/lib/foundation/specifications/widget_type.dart
Added selectableText member to WidgetType.
Parser & registration
packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart, packages/stac/lib/src/parsers/widgets/widgets.dart, packages/stac/lib/src/framework/stac_service.dart
New StacSelectableTextParser added, exported and registered; builds nested TextSpan tree (per-span tap recognizers), resolves/merges styles, wires model-level onTap, and returns SelectableText.rich honoring cursor, selection, and other options.
Import cleanup
packages/stac/lib/src/parsers/.../*.dart
Removed several now-unused imports (stac_action_parser.dart, stac_widget_parser.dart) from multiple parser files.
Examples pubspecs
examples/counter_example/pubspec.yaml, examples/movie_app/pubspec.yaml, examples/stac_gallery/pubspec.yaml
Removed explicit version constraints for stac (and stac_core / stac_webview where present), leaving unpinned dependency entries.

Sequence Diagram(s)

sequenceDiagram
  participant JSON as JSON asset
  participant Service as StacService (registry)
  participant Parser as StacSelectableTextParser
  participant Model as StacSelectableText
  participant Flutter as Flutter SelectableText.rich
  participant Stac as Stac (action handler)

  JSON->>Service: request parse (type: selectableText)
  Service->>Parser: dispatch to selectableText parser
  Parser->>Model: StacSelectableText.fromJson(json)
  Parser->>Parser: build TextSpan tree (children, styles, per-span taps)
  Parser->>Flutter: return SelectableText.rich(textSpanTree, options)
  Note over Flutter: renders selectable text (cursor, selection, semantics)
  Flutter->>Stac: user taps span or widget (TapGestureRecognizer)
  Stac->>Stac: onCallFromJson invoked (resolve action)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect parser's TextSpan construction and TapGestureRecognizer lifecycle for proper disposal and no retained references.
  • Verify style merging precedence in the parser matches existing text-style semantics.
  • Confirm generated serialization names and enum mappings align with build setup.

Possibly related PRs

Suggested labels

feature

Suggested reviewers

  • divyanshub024
  • Potatomonsta

Poem

🐰 I nibbled docs and stitched a span,

Cursors gleam where selections began.
Rich hops of text in JSON light,
Taps call actions, tidy and bright.
Hooray — selectable delight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes include unrelated import removals from parser files and version constraint removals from pubspec.yaml files that are not related to SelectableText feature. Remove unrelated import cleanup changes (stac_set_value, stac_app_bar, stac_container, stac_inkwell, stac_switch parsers) and version constraint removals from pubspec.yaml files; focus on SelectableText implementation only.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly summarizes the main change: adding SelectableText widget support with parser, documentation, and examples.
Linked Issues check ✅ Passed All four requirements from issue #385 are met: SelectableText model created, parser implemented, documentation added, and example provided in Stac Gallery.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b76c463 and 74f8288.

📒 Files selected for processing (5)
  • docs/docs.json (1 hunks)
  • examples/stac_gallery/assets/json/home_screen.json (1 hunks)
  • packages/stac/lib/src/framework/stac_service.dart (1 hunks)
  • packages/stac_core/lib/foundation/specifications/widget_type.dart (1 hunks)
  • packages/stac_core/lib/widgets/widgets.dart (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/docs.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/stac_core/lib/foundation/specifications/widget_type.dart
  • examples/stac_gallery/assets/json/home_screen.json
  • packages/stac/lib/src/framework/stac_service.dart
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-19T20:20:55.561Z
Learnt from: akhil-ge0rge
Repo: StacDev/stac PR: 399
File: packages/stac/lib/src/parsers/theme/stac_tool_tip_theme_data_parser.dart:9-26
Timestamp: 2025-12-19T20:20:55.561Z
Learning: In Flutter, TooltipThemeData.height is deprecated since v3.30.0-0.1.pre. Replace uses with TooltipThemeData.constraints: BoxConstraints(minHeight: value) to achieve the same minimum height. Apply this pattern to review any Dart/Flutter code that uses TooltipThemeData.height, not just this file.

Applied to files:

  • packages/stac_core/lib/widgets/widgets.dart
🔇 Additional comments (1)
packages/stac_core/lib/widgets/widgets.dart (1)

64-64: LGTM! Properly positioned export for the new SelectableText widget.

The export statement is syntactically correct, follows the established naming convention, and is correctly positioned in alphabetical order between 'scaffold' and 'set_value'.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
docs/widgets/selectable_text.mdx (1)

13-14: Clarify the relationship between data and children properties.

The documentation lists both data (for plain text) and children (for rich text with multiple spans), but doesn't explain that these represent two different usage patterns—similar to Flutter's SelectableText vs SelectableText.rich constructors. Consider adding a note that these are mutually exclusive.

packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (1)

53-68: Gesture recognizers in child spans are not disposed.

TapGestureRecognizer instances created in _buildTextSpan are not explicitly disposed. While Flutter's RichText (underlying SelectableText.rich) does dispose recognizers when the widget is unmounted, this relies on internal behavior that may not hold in all scenarios (e.g., widget rebuilds with different children).

Consider caching recognizers in a stateful widget or documenting the reliance on Flutter's internal disposal. For a stateless parser, the current approach is generally acceptable but worth noting for maintainability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 460a4c1 and b8660f6.

📒 Files selected for processing (10)
  • docs/docs.json (1 hunks)
  • docs/widgets/selectable_text.mdx (1 hunks)
  • examples/stac_gallery/assets/json/home_screen.json (1 hunks)
  • examples/stac_gallery/assets/json/selectable_text_example.json (1 hunks)
  • packages/stac/lib/src/framework/stac_service.dart (1 hunks)
  • packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (1 hunks)
  • packages/stac/lib/src/parsers/widgets/widgets.dart (1 hunks)
  • packages/stac_core/lib/foundation/specifications/widget_type.dart (1 hunks)
  • packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (1 hunks)
  • packages/stac_core/lib/widgets/widgets.dart (1 hunks)
🔇 Additional comments (14)
docs/widgets/selectable_text.mdx (1)

25-25: Verify the cursorRadius type specification.

The documentation specifies cursorRadius as double?, but Flutter's SelectableText API expects a Radius? object. Confirm whether the parser accepts a single double value and converts it to a Radius, or if this should be documented differently.

docs/docs.json (1)

140-140: LGTM! Selectable text documentation properly integrated.

The placement after "text" makes semantic sense, grouping text-related widgets together.

packages/stac_core/lib/widgets/widgets.dart (1)

64-64: LGTM! Export correctly placed in alphabetical order.

The new selectable_text export is properly positioned between scaffold and set_value, maintaining the file's alphabetical organization.

packages/stac/lib/src/parsers/widgets/widgets.dart (1)

60-60: LGTM! Parser export correctly placed in alphabetical order.

The new parser export maintains the file's alphabetical organization and aligns with the corresponding widget export.

packages/stac/lib/src/framework/stac_service.dart (1)

131-131: LGTM! Parser registered in the framework.

The StacSelectableTextParser is properly instantiated and added to the global parsers list, enabling JSON-based parsing of selectable text widgets.

examples/stac_gallery/assets/json/home_screen.json (1)

822-843: LGTM! Gallery entry properly configured.

The new list tile for Selectable Text is well-placed after the Text widget, uses an appropriate icon, and correctly navigates to the example file.

packages/stac_core/lib/foundation/specifications/widget_type.dart (1)

192-193: LGTM! Enum member correctly added in alphabetical order.

The selectableText enum member is properly positioned and documented, maintaining consistency with the existing enum structure.

examples/stac_gallery/assets/json/selectable_text_example.json (1)

1-117: Excellent example coverage demonstrating key SelectableText features.

The example file effectively showcases:

  • Basic selectable text usage
  • Rich text with styled children
  • Cursor customization
  • Disabling interactive selection

The structure is clear and well-organized with appropriate spacing between examples.

packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (1)

14-22: LGTM!

Parser class structure follows the established pattern with const constructor, type getter, and getModel delegation.

packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (5)

1-10: LGTM!

Imports are appropriate and the part directive correctly references the generated JSON serialization file.


12-42: Documentation is thorough and helpful.

The doc comments with both Dart and JSON examples provide clear usage guidance for developers.


43-67: LGTM!

Constructor follows the established pattern with data as the only required field, matching Flutter's SelectableText API where the text content is mandatory.


126-127: selectionColor may not be directly applicable.

As noted in the parser review, Flutter's SelectableText does not expose a direct selectionColor parameter. The selection color is typically controlled via TextSelectionTheme. Consider verifying whether this field can be utilized or should be removed to avoid confusion.


129-138: LGTM!

The type getter and JSON serialization methods follow the established widget pattern.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (1)

92-93: Clarify textScaler documentation.

The documentation says "font scaling strategy" but the field type is double?, representing a scale factor (similar to textScaleFactor), not a TextScaler object. The parser converts this to TextScaler.linear() during rendering.

Consider updating the documentation to clarify:

-  /// The font scaling strategy to use.
+  /// The text scale factor to use (converted to TextScaler.linear during rendering).
   final double? textScaler;

Alternatively, if the field name textScaler is meant to align with Flutter's API terminology, add a note explaining that it stores the numeric scale factor for JSON serialization purposes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8660f6 and d9890d7.

📒 Files selected for processing (5)
  • docs/docs.json (1 hunks)
  • docs/widgets/selectable_text.mdx (1 hunks)
  • examples/stac_gallery/assets/json/selectable_text_example.json (1 hunks)
  • packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (1 hunks)
  • packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/widgets/selectable_text.mdx
  • examples/stac_gallery/assets/json/selectable_text_example.json
🔇 Additional comments (6)
docs/docs.json (1)

136-136: LGTM!

The navigation entry for the new SelectableText widget documentation is correctly placed in the Data Widgets group.

packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (3)

1-22: LGTM!

The parser structure follows the standard pattern with proper imports and type registration.


24-54: LGTM! All previous issues addressed.

The parse method correctly:

  • Includes selectionColor parameter (previously missing)
  • Defaults textScaler to null to preserve system accessibility scaling (previously used TextScaler.noScaling)
  • Handles both the new textScaler and deprecated textScaleFactor fields
  • Maps all model properties to the SelectableText.rich widget

56-71: LGTM!

The TextSpan construction correctly handles hierarchical text with per-child styles and tap handlers.

packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (2)

1-42: LGTM!

The documentation is comprehensive with clear examples in both Dart and JSON formats, properly illustrating the widget's usage.


134-143: LGTM!

The type getter and JSON serialization methods follow the standard pattern with proper code generation setup.

@divyanshub024
Copy link
Member

Hey @xkaper001 !! The PR checks are failing. Can you please check?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
examples/movie_app/pubspec.yaml (1)

37-38: Same concern as in counter_example/pubspec.yaml.

The unpinned stac and stac_core dependencies should resolve to local workspace packages. This is already flagged for verification in the counter_example review.

examples/stac_gallery/pubspec.yaml (1)

40-41: Same concern as in counter_example/pubspec.yaml.

The unpinned stac and stac_webview dependencies should resolve to local workspace packages. This is already flagged for verification in the counter_example review.

packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (1)

34-36: Accessibility issue persists: default textScaler disables system scaling.

As flagged in previous reviews, setting textScaler to null when model.textScaler is absent allows Flutter to use the system's accessibility text scale factor. However, the current implementation would need to conditionally omit the parameter entirely rather than passing null, OR the SelectableText.rich constructor should handle null appropriately.

According to Flutter's API, when textScaler is omitted, the widget inherits from MediaQuery. Passing an explicit value (even null) may override this behavior depending on the Flutter version.

Does Flutter SelectableText.rich textScaler parameter accept null to use MediaQuery default?
🧹 Nitpick comments (1)
packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (1)

87-88: Clarify textScaler field documentation.

The textScaler field is documented as "The font scaling strategy" but it's typed as double?. This differs from Flutter's SelectableText.textScaler which expects a TextScaler object. Consider documenting that this double value will be converted to TextScaler.linear() by the parser, or note the relationship to the deprecated textScaleFactor parameter.

📝 Suggested documentation improvement
-  /// The font scaling strategy to use.
+  /// The font scaling factor to apply to text.
+  ///
+  /// This value is converted to [TextScaler.linear] during parsing.
+  /// When null, the widget uses the system's text scale factor from [MediaQuery].
   final double? textScaler;
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3378c73 and b76c463.

📒 Files selected for processing (6)
  • examples/counter_example/pubspec.yaml (1 hunks)
  • examples/movie_app/pubspec.yaml (1 hunks)
  • examples/stac_gallery/pubspec.yaml (1 hunks)
  • packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (1 hunks)
  • packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (1 hunks)
  • packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.g.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-19T20:20:55.561Z
Learnt from: akhil-ge0rge
Repo: StacDev/stac PR: 399
File: packages/stac/lib/src/parsers/theme/stac_tool_tip_theme_data_parser.dart:9-26
Timestamp: 2025-12-19T20:20:55.561Z
Learning: In Flutter, TooltipThemeData.height is deprecated since v3.30.0-0.1.pre. Replace uses with TooltipThemeData.constraints: BoxConstraints(minHeight: value) to achieve the same minimum height. Apply this pattern to review any Dart/Flutter code that uses TooltipThemeData.height, not just this file.

Applied to files:

  • packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart
  • packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart
  • packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.g.dart
🔇 Additional comments (7)
packages/stac/lib/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart (3)

47-47: Good: selectionColor parameter added.

The previous review comment about missing selectionColor has been addressed. The parameter is now correctly passed to SelectableText.rich.


81-81: Good: Style resolution fixed for null base.

The previous issue where overrideParsed was discarded when baseStyle is null has been resolved. The method now correctly returns overrideParsed in this case.


54-69: LGTM: TextSpan tree construction is correct.

The _buildTextSpan method properly constructs a nested TextSpan tree from the model, correctly handling:

  • Root text (model.data)
  • Child spans with individual styles
  • Per-child tap gesture recognizers via TapGestureRecognizer
packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.g.dart (1)

1-91: LGTM: Generated JSON serialization code.

The generated code correctly implements:

  • fromJson with proper null handling and type conversions
  • toJson with all fields including the type discriminator
  • Enum mappings for StacTextAlign, StacTextDirection, and StacTextWidthBasis

As this is generated code, no manual changes should be made here.

packages/stac_core/lib/widgets/selectable_text/stac_selectable_text.dart (2)

12-42: LGTM: Clear documentation with examples.

The documentation provides helpful Dart and JSON examples that demonstrate typical usage of the StacSelectableText widget. The examples are concise and cover key properties.


43-139: LGTM: Well-structured widget model.

The StacSelectableText class is properly structured with:

  • Comprehensive parameter set matching Flutter's SelectableText
  • Proper JSON serialization annotations
  • Type discriminator via WidgetType.selectableText.name
  • Clear field documentation
examples/counter_example/pubspec.yaml (1)

37-37: Dependency resolution for stac is correctly configured via Melos monorepo pattern.

The empty version constraint in pubspec.yaml works in conjunction with pubspec_overrides.yaml, which is the standard pattern for managing dependencies in pub workspaces/monorepos. The pubspec_overrides.yaml file explicitly provides a path override (path: ../../packages/stac), ensuring the example always resolves to the local workspace package. This is the intended design for this Melos-based monorepo and does not cause instability.

Likely an incorrect or invalid review comment.

@xkaper001
Copy link
Contributor Author

xkaper001 commented Dec 21, 2025

@divyanshub024 Does it look good?

Copy link
Member

@divyanshub024 divyanshub024 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution, @xkaper001 🎉 💯

@divyanshub024 divyanshub024 merged commit 19f0ea7 into StacDev:dev Dec 21, 2025
5 checks passed
@xkaper001 xkaper001 deleted the issue385 branch December 21, 2025 14:55
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.

feat: Add support for SelectableText widget

3 participants