TTableHeader<T, K>.values constructor

TTableHeader<T, K>.values(
  1. String text,
  2. List<TKeyValue> builder(
    1. T
    ), {
  3. int? flex,
  4. double? minWidth,
  5. double? maxWidth,
  6. Alignment? alignment,
  7. double spacing = 2.0,
  8. CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.start,
  9. MainAxisAlignment mainAxisAlignment = MainAxisAlignment.center,
  10. bool flattenOnMobile = true,
  11. String mobileKeyPrefixBuilder(
    1. String headerText,
    2. String childKey
    )?,
  12. String? key,
  13. TFilterType? filterType,
  14. bool filterable = false,
  15. List<TFilterOperator>? filterOperators,
  16. List? filterItems,
  17. TFilterDef<T>? filterDef,
  18. double widthEstimator(
    1. T data
    )?,
})

Creates a header for displaying a list of values with hierarchical font sizes and adaptive contrast in table cells, automatically flattened on mobile card views.

Hierarchical styling by index:

  • 1st value (index 0): size multiplier 1.015, color same as contentTextStyle
  • 2nd value (index 1): size multiplier 0.85, color adaptiveContrast(ctx, -0.5)
  • 3rd value (index 2): size multiplier 0.7, color adaptiveContrast(ctx, -0.85)
  • 4th+ values (index >= 3): size multiplier 0.55, color adaptiveContrast(ctx, -1.0)

Implementation

TTableHeader.values(
  this.text,
  List<TKeyValue> Function(T) builder, {
  this.flex,
  this.minWidth,
  this.maxWidth,
  this.alignment,
  double spacing = 2.0,
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.start,
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.center,
  this.flattenOnMobile = true,
  this.mobileKeyPrefixBuilder,
  this.key,
  this.filterType,
  this.filterable = false,
  this.filterOperators,
  this.filterItems,
  this.filterDef,
  double Function(T data)? widthEstimator,
})  : map = null,
      keyValuesBuilder = builder,
      widthEstimator = widthEstimator ??
          ((data) {
            final items = builder(data);
            if (items.isEmpty) return 0.0;
            double maxWidth = 0.0;
            for (int i = 0; i < items.length; i++) {
              final kv = items[i];
              final displayValue = kv.value ?? kv.key;
              final double sizeMultiplier = switch (i) {
                0 => 1.015,
                1 => 0.85,
                2 => 0.7,
                _ => 0.55,
              };
              final style = TTableTheme.fallbackTextStyle.adjust(sizeMultiplier: sizeMultiplier);
              var itemWidth = TTableTheme.measureTextWidth(displayValue, style);
              if (kv.icon != null) itemWidth += 20.0;
              if (itemWidth > maxWidth) maxWidth = itemWidth;
            }
            return maxWidth;
          }),
      builder = ((ctx, item, __) {
        final scope = TTableScope.maybeOf(ctx);
        final isDense = scope?.dense ?? false;
        final items = builder(item.data);
        if (items.isEmpty) return const SizedBox.shrink();

        final contentStyle =
            scope?.contentTextStyle ?? ctx.theme.tableTheme.rowCardTheme.contentTextStyle ?? const TextStyle(fontSize: 13.6);

        final effectiveSpacing = isDense ? spacing * 0.75 : spacing;

        TextStyle? getLevelStyle(int index) {
          final double sizeMultiplier;
          final double? contrast;

          switch (index) {
            case 0:
              sizeMultiplier = 1.015;
              contrast = null;
              break;
            case 1:
              sizeMultiplier = 0.85;
              contrast = -0.5;
              break;
            case 2:
              sizeMultiplier = 0.7;
              contrast = -0.85;
              break;
            default:
              sizeMultiplier = 0.55;
              contrast = -1.0;
              break;
          }

          final baseColor = contentStyle.color;
          final targetColor = (contrast != null && baseColor != null) ? baseColor.adaptiveContrast(ctx, contrast) : baseColor;

          return contentStyle.adjust(
            sizeMultiplier: sizeMultiplier,
            color: targetColor,
          );
        }

        Widget buildItemWidget(TKeyValue kv, int index) {
          final levelStyle = getLevelStyle(index);
          final displayValue = kv.value ?? kv.key;

          Widget content;
          if (kv.widget != null) {
            content = DefaultTextStyle(
              style: levelStyle ?? const TextStyle(),
              child: kv.widget!,
            );
          } else {
            content = Text(
              displayValue,
              style: levelStyle,
              overflow: TextOverflow.ellipsis,
            );
          }

          if (kv.icon != null) {
            return Row(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                kv.icon!,
                const SizedBox(width: 4),
                Flexible(child: content),
              ],
            );
          }

          return content;
        }

        return Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: mainAxisAlignment,
          crossAxisAlignment: crossAxisAlignment,
          children: [
            for (int i = 0; i < items.length; i++) ...[
              if (i > 0) SizedBox(height: effectiveSpacing),
              buildItemWidget(items[i], i),
            ],
          ],
        );
      });