Skip to content

prefactor: generalize filterable index layout and components - #13768

Open
ericwindmill wants to merge 9 commits into
mainfrom
refactor-filterable-index
Open

prefactor: generalize filterable index layout and components#13768
ericwindmill wants to merge 9 commits into
mainfrom
refactor-filterable-index

Conversation

@ericwindmill

@ericwindmill ericwindmill commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Description of what this PR is changing or adding, and why:

Extract generic two-column filterable index layout styles and sidebar/search components from learning resources index into reusable filterable_index.dart and _filterable-index.scss.

This change anticipates new content for FlutterBench, where I'm adding a CUJ index #13691

Extract generic two-column filterable index layout styles and sidebar/search
components from learning resources into reusable filterable_index.dart
and _filterable-index.scss.
@ericwindmill
ericwindmill requested review from a team and sfshaza2 as code owners August 20, 2026 19:07

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the filterable index pages by extracting shared layout, sidebar, and search group components and styles into reusable Dart components (FiltersSidebar, FilterSearchGroup) and a shared SASS stylesheet (_filterable-index.scss), successfully reducing code duplication. The feedback highlights a critical issue in filterable_index.dart where event.target is unsafely cast to web.Element? using the 'as' operator, which can lead to a runtime TypeError. It is recommended to use a safe type check (is web.Element) instead.

Comment on lines +133 to +139
onClick: (event) {
final target = event.target as web.Element?;
if (target?.closest(_sidebarSelector) == null &&
target?.closest('.show-filters-button') == null) {
_toggle?.checked = false;
}
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Casting event.target directly to web.Element? using as is unsafe and can throw a TypeError at runtime. In the DOM, event.target can be a Document, Window, or other non-element nodes (for example, if the user clicks on a scrollbar or outside the window). To prevent runtime crashes, use a safe type check (is web.Element) before calling element-specific methods like closest.

      onClick: (event) {
        final target = event.target;
        final element = target is web.Element ? target : null;
        if (element?.closest(_sidebarSelector) == null &&
            element?.closest('.show-filters-button') == null) {
          _toggle?.checked = false;
        }
      },

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is this not exactly the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The underlying of the comment is sort of right, but its solution isn't accurate since is also doesn't work for web types. Instead use the isA method. Something like this:

onClick: (event) {
  final target = event.target;
  if (target == null || !target.isA<web.Element>()) return;

  final element = target as web.Element;
  if (element.closest(_sidebarSelector) == null &&
      element.closest('.show-filters-button') == null) {
    _toggle?.checked = false;
  }
},

@ericwindmill
ericwindmill requested a review from parlough August 20, 2026 19:09
@flutter-website-bot

flutter-website-bot commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Staged preview of the updated docs.flutter.dev site (updated for commit c932533):

https://flutter-docs-prod--docs-pr13768-refactor-filterable-in-fnqqj8yi.web.app

@flutter-website-bot

flutter-website-bot commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Staged preview of the updated flutter.dev site (updated for commit c932533):

https://flutter-dev-230821--www-pr13768-refactor-filterable-in-6oidcs4i.web.app

@parlough parlough left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for extracting this out @ericwindmill! Mostly looks good to me.

Should the learning resources index be updated to use the new FilterSearchGroup?

Comment thread sites/docs/lib/src/components/pages/filterable_index.dart
Comment thread sites/docs/lib/src/components/pages/filterable_index.dart
Comment on lines +133 to +139
onClick: (event) {
final target = event.target as web.Element?;
if (target?.closest(_sidebarSelector) == null &&
target?.closest('.show-filters-button') == null) {
_toggle?.checked = false;
}
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The underlying of the comment is sort of right, but its solution isn't accurate since is also doesn't work for web types. Instead use the isA method. Something like this:

onClick: (event) {
  final target = event.target;
  if (target == null || !target.isA<web.Element>()) return;

  final element = target as web.Element;
  if (element.closest(_sidebarSelector) == null &&
      element.closest('.show-filters-button') == null) {
    _toggle?.checked = false;
  }
},

Comment thread sites/docs/lib/src/components/pages/filterable_index.dart Outdated
Comment thread sites/docs/lib/src/components/pages/filterable_index.dart
Comment thread sites/docs/lib/_sass/components/_filterable-index.scss
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.

3 participants