Skip to content

Support value-semantic custom ContextVariant types #1014

Description

@leoafarias

Use case

ContextVariant accepts an arbitrary bool Function(BuildContext) and therefore retains identity equality. When a pure style factory constructs the same logical custom variant on each invocation, the resulting styles compare unequal and their variants do not share merge identity.

This surfaced in conceptadev/remix#121: CheckboxStyler.onIndeterminate created the same logical variant on every call, but each instance contained a new closure. conceptadev/remix#124 works around it by reusing a single variant instance.

Downstream custom variants currently have two choices:

  • retain a shared singleton; or
  • subclass ContextVariant and repeat operator ==/hashCode boilerplate already implemented independently by Mix's built-in variants.

Using ContextVariant.key as equality is unsafe because Mix documents it as a human-readable diagnostic label and deliberately keeps it out of semantic merge identity.

Relevant implementation:

Proposal

Provide an opt-in API for custom context variants with explicit value semantics while preserving the identity behavior of the existing ContextVariant constructor.

One possible API is an abstract base class:

abstract base class ValueContextVariant extends ContextVariant {
  const ValueContextVariant(super.key, super.shouldApply);

  List<Object?> get props => const [];

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other.runtimeType == runtimeType &&
          other is ValueContextVariant &&
          propsEquals(props, other.props);

  @override
  int get hashCode => propsHash(runtimeType, props);
}

Proposed downstream usage:

final class IndeterminateVariant extends ValueContextVariant {
  const IndeterminateVariant()
      : super('on_indeterminate', _shouldApply);

  static bool _shouldApply(BuildContext context) {
    return CheckboxState.maybeOf(context)?.isChecked == null;
  }
}

The exact API could instead be a constructor/factory accepting an explicit semantic identity. The important requirements are:

  • existing directly constructed ContextVariants retain identity semantics;
  • custom variants can opt into consistent equality and hash codes;
  • semantic identity is separate from the diagnostic key;
  • different variant types or value properties cannot collide accidentally;
  • VariantStyle equality and merge behavior honor the custom value semantics;
  • tests cover equal instances, unequal properties, identical diagnostic keys with distinct identities, and unchanged built-in variant behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions