libmonet 2.0.0-dev.17 copy "libmonet: ^2.0.0-dev.17" to clipboard
libmonet: ^2.0.0-dev.17 copied to clipboard

Algorithms and utilities that power the Material Design 3 (M3) color system, including choosing theme colors from images and creating tones of colors; all in a new color space.

example/main.dart

// ignore_for_file: avoid_print

import 'dart:convert';
import 'dart:io' as io;

import 'package:change_case/change_case.dart';
import 'package:libmonet/libmonet.dart';
import 'package:path/path.dart' as p;

import 'src/figma.dart' as figma;

const _specVersionToVariants = <SpecVersion, Set<Variant>>{
  .spec2021: {
    .monochrome,
    .neutral,
    .tonalSpot,
    .vibrant,
    .expressive,
    .fidelity,
    .content,
    .rainbow,
    .fruitSalad,
  },
  .spec2025: {.neutral, .tonalSpot, .vibrant, .expressive},
  .spec2026: {.cmf},
};

const _specVersionToPlatforms = <SpecVersion, Set<Platform>>{
  .spec2021: {.phone},
  .spec2025: {.phone, .watch},
  .spec2026: {.phone},
};

extension type _SeedColors._(
  ({
    TonalPaletteSourceColor sourceColor,
    TonalPaletteSourceColor? primaryPaletteKeyColor,
    TonalPaletteSourceColor? secondaryPaletteKeyColor,
    TonalPaletteSourceColor? tertiaryPaletteKeyColor,
    TonalPaletteSourceColor? neutralPaletteKeyColor,
    TonalPaletteSourceColor? neutralVariantPaletteKeyColor,
    TonalPaletteSourceColor? errorPaletteKeyColor,
  })
  _
) implements Object {
  const _SeedColors({
    required TonalPaletteSourceColor sourceColor,
    TonalPaletteSourceColor? primaryPaletteKeyColor,
    TonalPaletteSourceColor? secondaryPaletteKeyColor,
    TonalPaletteSourceColor? tertiaryPaletteKeyColor,
    TonalPaletteSourceColor? neutralPaletteKeyColor,
    TonalPaletteSourceColor? neutralVariantPaletteKeyColor,
    TonalPaletteSourceColor? errorPaletteKeyColor,
  }) : _ = (
         sourceColor: sourceColor,
         primaryPaletteKeyColor: primaryPaletteKeyColor,
         secondaryPaletteKeyColor: secondaryPaletteKeyColor,
         tertiaryPaletteKeyColor: tertiaryPaletteKeyColor,
         neutralPaletteKeyColor: neutralPaletteKeyColor,
         neutralVariantPaletteKeyColor: neutralVariantPaletteKeyColor,
         errorPaletteKeyColor: errorPaletteKeyColor,
       );

  TonalPaletteSourceColor get sourceColor => _.sourceColor;

  TonalPaletteSourceColor? get primaryPaletteKeyColor =>
      _.primaryPaletteKeyColor;

  TonalPaletteSourceColor? get secondaryPaletteKeyColor =>
      _.secondaryPaletteKeyColor;

  TonalPaletteSourceColor? get tertiaryPaletteKeyColor =>
      _.tertiaryPaletteKeyColor;

  TonalPaletteSourceColor? get neutralPaletteKeyColor =>
      _.neutralPaletteKeyColor;

  TonalPaletteSourceColor? get neutralVariantPaletteKeyColor =>
      _.neutralVariantPaletteKeyColor;

  TonalPaletteSourceColor? get errorPaletteKeyColor => _.errorPaletteKeyColor;
}

final seedColorsByName = <String, _SeedColors>{
  "baseline": .new(sourceColor: .fromArgb(0xFF6750A4)),
  // "nowinandroid": .new(
  //   sourceColor: .fromArgb(0xFF8C4190),
  //   primaryPaletteKeyColor: .fromArgb(0xFF8C4190),
  //   secondaryPaletteKeyColor: .fromArgb(0xFFFF8456),
  //   tertiaryPaletteKeyColor: .fromArgb(0xFFB3E9FF),
  //   neutralPaletteKeyColor: .fromArgb(0xFF201A1B),
  // ),
};

final _mdc = MaterialDynamicColors();
final _adc = AndroidDynamicColors();

final _materialDynamicColors = <DynamicColor>{
  _mdc.primaryPaletteKeyColor,
  _mdc.secondaryPaletteKeyColor,
  _mdc.tertiaryPaletteKeyColor,
  _mdc.neutralPaletteKeyColor,
  _mdc.neutralVariantPaletteKeyColor,
  _mdc.errorPaletteKeyColor,
  _mdc.background,
  _mdc.onBackground,
  _mdc.surface,
  _mdc.surfaceDim,
  _mdc.surfaceBright,
  _mdc.surfaceContainerLowest,
  _mdc.surfaceContainerLow,
  _mdc.surfaceContainer,
  _mdc.surfaceContainerHigh,
  _mdc.surfaceContainerHighest,
  _mdc.onSurface,
  _mdc.surfaceVariant,
  _mdc.onSurfaceVariant,
  _mdc.outline,
  _mdc.outlineVariant,
  _mdc.inverseSurface,
  _mdc.inverseOnSurface,
  _mdc.shadow,
  _mdc.scrim,
  _mdc.surfaceTint,
  _mdc.primary,
  _mdc.primaryDim,
  _mdc.onPrimary,
  _mdc.primaryContainer,
  _mdc.onPrimaryContainer,
  _mdc.primaryFixed,
  _mdc.primaryFixedDim,
  _mdc.onPrimaryFixed,
  _mdc.onPrimaryFixedVariant,
  _mdc.inversePrimary,
  _mdc.secondary,
  _mdc.secondaryDim,
  _mdc.onSecondary,
  _mdc.secondaryContainer,
  _mdc.onSecondaryContainer,
  _mdc.secondaryFixed,
  _mdc.secondaryFixedDim,
  _mdc.onSecondaryFixed,
  _mdc.onSecondaryFixedVariant,
  _mdc.tertiary,
  _mdc.tertiaryDim,
  _mdc.onTertiary,
  _mdc.tertiaryContainer,
  _mdc.onTertiaryContainer,
  _mdc.tertiaryFixed,
  _mdc.tertiaryFixedDim,
  _mdc.onTertiaryFixed,
  _mdc.onTertiaryFixedVariant,
  _mdc.error,
  _mdc.errorDim,
  _mdc.onError,
  _mdc.errorContainer,
  _mdc.onErrorContainer,
};

final _androidOnlyDynamicColors = <DynamicColor>{
  _mdc.controlActivated,
  _mdc.controlNormal,
  _mdc.controlHighlight,
  _mdc.textPrimaryInverse,
  _mdc.textSecondaryAndTertiaryInverse,
  _mdc.textPrimaryInverseDisableOnly,
  _mdc.textSecondaryAndTertiaryInverseDisabled,
  _mdc.textHintInverse,
};

final _androidCustomDynamicColors = <DynamicColor>{
  _adc.widgetBackground,
  _adc.clockHour,
  _adc.clockMinute,
  _adc.clockSecond,
  _adc.weatherTemp,
  _adc.themeApp,
  _adc.onThemeApp,
  _adc.themeAppRing,
  _adc.themeNotif,
  _adc.brandA,
  _adc.brandB,
  _adc.brandC,
  _adc.brandD,
  _adc.underSurface,
  _adc.shadeActive,
  _adc.onShadeActive,
  _adc.onShadeActiveVariant,
  _adc.shadeInactive,
  _adc.onShadeInactive,
  _adc.onShadeInactiveVariant,
  _adc.shadeDisabled,
  _adc.overviewBackground,
  _adc.surfaceEffect0,
  _adc.surfaceEffect1,
  _adc.surfaceEffect2,
  _adc.surfaceEffect3,
  _adc.surfaceEffect0Fallback,
};

final _allDynamicColors = <DynamicColor>{
  ..._materialDynamicColors,
  ..._androidOnlyDynamicColors,
  ..._androidCustomDynamicColors,
};

extension type const _DynamicSchemeConfiguration._(
  ({Variant variant, Platform platform, SpecVersion specVersion}) _
) implements Object {
  const _DynamicSchemeConfiguration({
    required Variant variant,
    required Platform platform,
    required SpecVersion specVersion,
  }) : _ = (variant: variant, platform: platform, specVersion: specVersion);

  Variant get variant => _.variant;

  Platform get platform => _.platform;

  SpecVersion get specVersion => _.specVersion;
}
String _cssHexFromArgb(int argb) {
  final rgbHex =
      "${ColorUtils.redFromArgb(argb).toRadixString(16).toUpperCase().padLeft(2, "0")}"
      "${ColorUtils.greenFromArgb(argb).toRadixString(16).toUpperCase().padLeft(2, "0")}"
      "${ColorUtils.blueFromArgb(argb).toRadixString(16).toUpperCase().padLeft(2, "0")}";
  return ColorUtils.isOpaque(argb)
      ? "#$rgbHex"
      : "#$rgbHex${ColorUtils.alphaFromArgb(argb).toRadixString(16).toUpperCase().padLeft(2, "0")}";
}

void main() {
  for (final MapEntry(key: name, value: seed) in seedColorsByName.entries) {
    final configurations = <_DynamicSchemeConfiguration>{};
    for (final rawSpecVersion in SpecVersion.values) {
      for (final rawPlatform in Platform.values) {
        for (final rawVariant in Variant.values) {
          final DynamicScheme(
            :variant,
            :platform,
            :specVersion,
          ) = DynamicScheme.withDefaults(
            variant: rawVariant,
            platform: rawPlatform,
            specVersion: rawSpecVersion,
          );
          final configuration = _DynamicSchemeConfiguration(
            variant: variant,
            platform: platform,
            specVersion: specVersion,
          );
          if (!configurations.add(configuration)) continue;

          final lightNormalContrast = DynamicScheme.withDefaults(
            sourceColor: seed.sourceColor,
            variant: variant,
            isDark: false,
            contrastLevel: 0.0,
            platform: platform,
            specVersion: specVersion,
          );
          final lightMediumContrast = DynamicScheme.withDefaults(
            sourceColor: seed.sourceColor,
            variant: variant,
            isDark: false,
            contrastLevel: 0.5,
            platform: platform,
            specVersion: specVersion,
          );
          final lightHighContrast = DynamicScheme.withDefaults(
            sourceColor: seed.sourceColor,
            variant: variant,
            isDark: false,
            contrastLevel: 1.0,
            platform: platform,
            specVersion: specVersion,
          );
          final darkNormalContrast = DynamicScheme.withDefaults(
            sourceColor: seed.sourceColor,
            variant: variant,
            isDark: true,
            contrastLevel: 0.0,
            platform: platform,
            specVersion: specVersion,
          );
          final darkMediumContrast = DynamicScheme.withDefaults(
            sourceColor: seed.sourceColor,
            variant: variant,
            isDark: true,
            contrastLevel: 0.5,
            platform: platform,
            specVersion: specVersion,
          );
          final darkHighContrast = DynamicScheme.withDefaults(
            sourceColor: seed.sourceColor,
            variant: variant,
            isDark: true,
            contrastLevel: 1.0,
            platform: platform,
            specVersion: specVersion,
          );

          final fileNameWithoutExtension =
              "${name}_${variant.name.toLowerCase()}_${specVersion.year}_${platform.name.toLowerCase()}";
          final packageRoot = io.Platform.script.resolve("../").toFilePath();

          {
            final theme = figma.Theme(
              description:
                  "TYPE: CUSTOM\n"
                  "Material Theme Builder export",
              seed: seed.sourceColor.asArgb,
              coreColors: figma.CoreColors(
                primary:
                    (seed.primaryPaletteKeyColor ?? seed.sourceColor).asArgb,
                secondary: seed.secondaryPaletteKeyColor?.asArgb,
                tertiary: seed.tertiaryPaletteKeyColor?.asArgb,
                neutral: seed.neutralPaletteKeyColor?.asArgb,
                neutralVariant: seed.neutralVariantPaletteKeyColor?.asArgb,
                error: seed.errorPaletteKeyColor?.asArgb,
              ),
              schemes: figma.Schemes.fromDynamicSchemes(
                light: lightNormalContrast,
                lightMediumContrast: lightMediumContrast,
                lightHighContrast: lightHighContrast,
                dark: darkNormalContrast,
                darkMediumContrast: darkMediumContrast,
                darkHighContrast: darkHighContrast,
              ),
            );
            final json = theme.toJson();
            final encoder = JsonEncoder.withIndent(" " * 2);
            final encoded = encoder.convert(json);

            print("$fileNameWithoutExtension / Figma");
            io.File(
                p.join(
                  packageRoot,
                  "example/generated/figma",
                  name,
                  "$fileNameWithoutExtension.json",
                ),
              )
              ..createSync(recursive: true)
              ..writeAsStringSync(encoded);
          }

          {
            final css = StringBuffer();

            void writeCssBuffer(String selector, DynamicScheme scheme) {
              css.writeln("$selector {");
              for (final dynamicColor in _allDynamicColors) {
                final variableName =
                    "md-sys-color-${dynamicColor.name.toKebabCase()}";
                final variableProperty = "--$variableName";
                final variableValue = _cssHexFromArgb(
                  dynamicColor.getArgb(scheme),
                );
                css.writeln("  $variableProperty: $variableValue;");
              }
              css.writeln("}");
            }

            writeCssBuffer(".light", lightNormalContrast);
            writeCssBuffer(".light-medium-contrast", lightMediumContrast);
            writeCssBuffer(".light-high-contrast", lightHighContrast);
            writeCssBuffer(".dark", darkNormalContrast);
            writeCssBuffer(".dark-medium-contrast", darkMediumContrast);
            writeCssBuffer(".dark-high-contrast", darkHighContrast);

            print("$fileNameWithoutExtension / CSS");

            io.File(
                p.join(
                  packageRoot,
                  "example/generated/css",
                  name,
                  "$fileNameWithoutExtension.css",
                ),
              )
              ..createSync(recursive: true)
              ..writeAsStringSync(css.toString());
          }
        }
      }
    }
  }
}
2
likes
140
points
313
downloads

Documentation

API reference

Publisher

verified publisherdeminearchiver.qzz.io

Weekly Downloads

Algorithms and utilities that power the Material Design 3 (M3) color system, including choosing theme colors from images and creating tones of colors; all in a new color space.

Homepage
Repository (GitHub)
View/report issues

Topics

#color #hct #material #android #utility

License

MIT (license)

Dependencies

collection, meta

More

Packages that depend on libmonet