Skip to content

Add a static function to Material UI widgets exposing internal default values #130135

@rydmike

Description

@rydmike

Is there an existing issue for this?

Use case

When making custom widgets, it is often useful to use default values from standard Material UI widgets as default fall-back values for the custom widget from its equivalent standard version's theme properties.

Doing that currently involves looking up the correct fallback value for such properties from its corresponding standard Material UI Widget in the source code from its private classes that implement these default values, and then add them as hard coded own constants for its own M2 and/or M3 mode values.

It would be very useful if we could access the private default values contained in Material UI component class files. They are typically found at the end of every UI widget having the name structure _ComponentDefaultsM2 and _ComponentDefaultsM3, where Component is the name of the Material UI widget in question.

Before Material3 was added, the UI widget default values where spread all over Widget build methods. Getting access to them was not feasible and even finding the default values was very difficult. However, the Material3 addition/migration cleaned up all this and extracted the default values into own private classes that the Material UI widgets access to get their defaults from. It would thus now easily be possible and very useful to offer these values also externally.

Proposal

One possible way of doing this would be to add a static default theme value getter to each UI widget. For example in the AppBar class we could have a static themeDefaults getter like:

  static AppBarTheme themeDefaults(BuildContext context) => 
      Theme.of(context).useMaterial3 
         ? _AppBarDefaultsM3(context) 
         : _AppBarDefaultsM2(context);

When we need to know what default values an AppBar widget uses, we could read that by getting the default values with:

  final AppBarTheme defaults = AppBar.themeDefaults(context);

Current Material UI components typically do this in their build, e.g. AppBar

final AppBarTheme defaults = theme.useMaterial3 ? _AppBarDefaultsM3(context) : _AppBarDefaultsM2(context);

They could use same static internally going forward:

  final AppBarTheme defaults = themeDefaults(context);

This was just one example, it should be added to all Material UI components that have default values provided via the private default value classes.

NOTE: The name of the static might need some consideration. We do no want the devs to confuse the defaults with the effective component theme of context values. To me themeDefaults work well, but themeFallback might be an alternative, or something else even, naming is hard 😄


EDIT: Add precedent info below

Precedent: DatePicker

There is already a precedent for this pattern. The DatePicker already offers it. However, the DatePicker also differs in implementation style from all other Material UI widgets. The DatePicker has the private default M2/M3 value classes in the component theme file date_picker_theme.dart and not in the component file date_picker.dart like all other Material component widgets do.

In the date_picker_theme.dart it has a static defaults in the DatePickerTheme, like so:

static DatePickerThemeData defaults(BuildContext context) {

  /// A DatePickerThemeData used as the default properties for date pickers.
  ///
  /// This is only used for properties not already specified in the ambient
  /// [DatePickerTheme.of].
  ///
  /// See also:
  ///
  ///  * [of], which will return [ThemeData.datePickerTheme] if it doesn't
  ///    find a [DatePickerTheme] ancestor, instead of returning null.
  ///  * [maybeOf], which returns null if it doesn't find a
  ///    [DatePickerTheme] ancestor.
  static DatePickerThemeData defaults(BuildContext context) {
    return Theme.of(context).useMaterial3
      ? _DatePickerDefaultsM3(context)
      : _DatePickerDefaultsM2(context);
  }

The DatePicker component implementation then use this static from the DatePickerTheme to get the defaults:

final DatePickerThemeData defaults = DatePickerTheme.defaults(context);

Why is DatePicker implementation different? Is the intent to migrate all Material UI components to this model?

The DatePickerTheme is one of the newest theme additions in the framework, so it would make sense if it is a new design, but it does not make sense if it is the only one using this pattern.

The static defaults certainly fits even better in the component theme class, than in the component class. Moving all the private default value classes to the theme classes certainly works very well too, even better. No objections there, as long as we can have access to them.


cc: @TahaTesser

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projectc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Fluttercustomer: crowdAffects or could affect many people, though not necessarily a specific customer.f: material designflutter/packages/flutter/material repository.f: themingStyling widgets with a themeframeworkflutter/packages/flutter repository. See also f: labels.team-designOwned by Design Languages teamtriaged-designTriaged by Design Languages teamwould be a good packageSeparate Flutter package should be made for this

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions