conceptadev / conceptadev/mix

Support value-semantic custom ContextVariant types

Open
#1,014 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
800
Forks
49
Avg merge
3h 39m
Merged PRs (30d)
22

Description

### 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`](https://github.com/conceptadev/remix/issues/121): `CheckboxStyler.onIndeterminate` created the same logical variant on every call, but each instance contained a new closure. [`conceptadev/remix#124`](https://github.com/conceptadev/remix/pull/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:

- [`ContextVariant` and its diagnostic key](https://github.com/conceptadev/mix/blob/ab7a9ab8507a49c530d0475d1a6e38f26b158d1e/packages/mix/lib/src/variants/variant.dart#L21-L55)
- [Context-variant merge identity](https://github.com/conceptadev/mix/blob/ab7a9ab8507a49c530d0475d1a6e38f26b158d1e/packages/mix/lib/src/core/style.dart#L276-L285)

### 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:

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

List 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:

```dart
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 `ContextVariant`s 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.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with ContextVariant and its diagnostic key in packages/mix/lib/src/variants/variant.dart, then trace context-variant merge identity in packages/mix/lib/src/core/style.dart. Compare the existing built-in variant equality behavior and decide on an opt-in value-semantics API without changing direct ContextVariant construction. Done means equal custom instances merge and compare equally, differing types or properties do not collide, and the requested equality and unchanged built-in behavior are covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, flutter
Domain
design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.