Class DynamicColor

java.lang.Object
org.glavo.monetfx.internal.dynamiccolor.DynamicColor

public final class DynamicColor extends Object
A color that adjusts itself based on UI state, represented by DynamicScheme.

This color automatically adjusts to accommodate a desired contrast level, or other adjustments such as differing in light mode versus dark mode, or what the theme is, or what the color that produced the theme is, etc.

Colors without backgrounds do not change tone when contrast changes. Colors with backgrounds become closer to their background as contrast lowers, and further when contrast increases.

Prefer the static constructors. They provide a much more simple interface, such as requiring just a hexcode, or just a hexcode and a background.

Ultimately, each component necessary for calculating a color, adjusting it for a desired contrast level, and ensuring it has a certain lightness/tone difference from another color, is provided by a function that takes a DynamicScheme and returns a value. This ensures ultimate flexibility, any desired behavior of a color for any design system, but it usually unnecessary. See the default constructor for more information.

  • Field Details

  • Constructor Details

    • DynamicColor

      public DynamicColor(@NotNull @NotNull String name, @NotNull @NotNull Function<DynamicScheme, TonalPalette> palette, @NotNull @NotNull Function<DynamicScheme, Double> tone, boolean isBackground, @Nullable @Nullable Function<DynamicScheme, DynamicColor> background, @Nullable @Nullable Function<DynamicScheme, DynamicColor> secondBackground, @Nullable @Nullable ContrastCurve contrastCurve, @Nullable @Nullable Function<DynamicScheme, ToneDeltaPair> toneDeltaPair)
      A constructor for DynamicColor.

      _Strongly_ prefer using one of the convenience constructors. This class is arguably too flexible to ensure it can support any scenario. Functional arguments allow overriding without risks that come with subclasses.

      For example, the default behavior of adjust tone at max contrast to be at a 7.0 ratio with its background is principled and matches accessibility guidance. That does not mean it's the desired approach for _every_ design system, and every color pairing, always, in every case.

      For opaque colors (colors with alpha = 100%).

      Parameters:
      name - The name of the dynamic color.
      palette - Function that provides a TonalPalette given DynamicScheme. A TonalPalette is defined by a hue and chroma, so this replaces the need to specify hue/chroma. By providing a tonal palette, when contrast adjustments are made, intended chroma can be preserved.
      tone - Function that provides a tone, given a DynamicScheme.
      isBackground - Whether this dynamic color is a background, with some other color as the foreground.
      background - The background of the dynamic color (as a function of a `DynamicScheme`), if it exists.
      secondBackground - A second background of the dynamic color (as a function of a `DynamicScheme`), if it exists.
      contrastCurve - A `ContrastCurve` object specifying how its contrast against its background should behave in various contrast levels options.
      toneDeltaPair - A `ToneDeltaPair` object specifying a tone delta constraint between two colors. One of them must be the color being constructed.
    • DynamicColor

      public DynamicColor(@NotNull @NotNull String name, @NotNull @NotNull Function<DynamicScheme, TonalPalette> palette, @NotNull @NotNull Function<DynamicScheme, Double> tone, boolean isBackground, @Nullable @Nullable Function<DynamicScheme, DynamicColor> background, @Nullable @Nullable Function<DynamicScheme, DynamicColor> secondBackground, @Nullable @Nullable ContrastCurve contrastCurve, @Nullable @Nullable Function<DynamicScheme, ToneDeltaPair> toneDeltaPair, @Nullable @Nullable Function<DynamicScheme, Double> opacity)
      A constructor for DynamicColor.

      _Strongly_ prefer using one of the convenience constructors. This class is arguably too flexible to ensure it can support any scenario. Functional arguments allow overriding without risks that come with subclasses.

      For example, the default behavior of adjust tone at max contrast to be at a 7.0 ratio with its background is principled and matches accessibility guidance. That does not mean it's the desired approach for _every_ design system, and every color pairing, always, in every case.

      For opaque colors (colors with alpha = 100%).

      Parameters:
      name - The name of the dynamic color.
      palette - Function that provides a TonalPalette given DynamicScheme. A TonalPalette is defined by a hue and chroma, so this replaces the need to specify hue/chroma. By providing a tonal palette, when contrast adjustments are made, intended chroma can be preserved.
      tone - Function that provides a tone, given a DynamicScheme.
      isBackground - Whether this dynamic color is a background, with some other color as the foreground.
      background - The background of the dynamic color (as a function of a `DynamicScheme`), if it exists.
      secondBackground - A second background of the dynamic color (as a function of a `DynamicScheme`), if it exists.
      contrastCurve - A `ContrastCurve` object specifying how its contrast against its background should behave in various contrast levels options.
      toneDeltaPair - A `ToneDeltaPair` object specifying a tone delta constraint between two colors. One of them must be the color being constructed.
      opacity - A function returning the opacity of a color, as a number between 0 and 1.
  • Method Details

    • fromPalette

      @NotNull public static @NotNull DynamicColor fromPalette(@NotNull @NotNull String name, @NotNull @NotNull Function<DynamicScheme, TonalPalette> palette, @NotNull @NotNull Function<DynamicScheme, Double> tone)
      A convenience constructor for DynamicColor.

      _Strongly_ prefer using one of the convenience constructors. This class is arguably too flexible to ensure it can support any scenario. Functional arguments allow overriding without risks that come with subclasses.

      For example, the default behavior of adjust tone at max contrast to be at a 7.0 ratio with its background is principled and matches accessibility guidance. That does not mean it's the desired approach for _every_ design system, and every color pairing, always, in every case.

      For opaque colors (colors with alpha = 100%).

      For colors that are not backgrounds, and do not have backgrounds.

      Parameters:
      name - The name of the dynamic color.
      palette - Function that provides a TonalPalette given DynamicScheme. A TonalPalette is defined by a hue and chroma, so this replaces the need to specify hue/chroma. By providing a tonal palette, when contrast adjustments are made, intended chroma can be preserved.
      tone - Function that provides a tone, given a DynamicScheme.
    • fromPalette

      @NotNull public static @NotNull DynamicColor fromPalette(@NotNull @NotNull String name, @NotNull @NotNull Function<DynamicScheme, TonalPalette> palette, @NotNull @NotNull Function<DynamicScheme, Double> tone, boolean isBackground)
      A convenience constructor for DynamicColor.

      _Strongly_ prefer using one of the convenience constructors. This class is arguably too flexible to ensure it can support any scenario. Functional arguments allow overriding without risks that come with subclasses.

      For example, the default behavior of adjust tone at max contrast to be at a 7.0 ratio with its background is principled and matches accessibility guidance. That does not mean it's the desired approach for _every_ design system, and every color pairing, always, in every case.

      For opaque colors (colors with alpha = 100%).

      For colors that do not have backgrounds.

      Parameters:
      name - The name of the dynamic color.
      palette - Function that provides a TonalPalette given DynamicScheme. A TonalPalette is defined by a hue and chroma, so this replaces the need to specify hue/chroma. By providing a tonal palette, when contrast adjustments are made, intended chroma can be preserved.
      tone - Function that provides a tone, given a DynamicScheme.
      isBackground - Whether this dynamic color is a background, with some other color as the foreground.
    • fromArgb

      @NotNull public static @NotNull DynamicColor fromArgb(@NotNull @NotNull String name, int argb)
      Create a DynamicColor from a hex code.

      Result has no background; thus no support for increasing/decreasing contrast for a11y.

      Parameters:
      name - The name of the dynamic color.
      argb - The source color from which to extract the hue and chroma.
    • getArgb

      public int getArgb(@NotNull @NotNull DynamicScheme scheme)
      Returns an ARGB integer (i.e. a hex code).
      Parameters:
      scheme - Defines the conditions of the user interface, for example, whether or not it is dark mode or light mode, and what the desired contrast level is.
    • getHct

      @NotNull public @NotNull Hct getHct(@NotNull @NotNull DynamicScheme scheme)
      Returns an HCT object.
      Parameters:
      scheme - Defines the conditions of the user interface, for example, whether or not it is dark mode or light mode, and what the desired contrast level is.
    • getTone

      public double getTone(@NotNull @NotNull DynamicScheme scheme)
      Returns the tone in HCT, ranging from 0 to 100, of the resolved color given scheme.
    • foregroundTone

      public static double foregroundTone(double bgTone, double ratio)
      Given a background tone, find a foreground tone, while ensuring they reach a contrast ratio that is as close to ratio as possible.
    • enableLightForeground

      public static double enableLightForeground(double tone)
      Adjust a tone down such that white has 4.5 contrast, if the tone is reasonably close to supporting it.
    • tonePrefersLightForeground

      public static boolean tonePrefersLightForeground(double tone)
      People prefer white foregrounds on ~T60-70. Observed over time, and also by Andrew Somers during research for APCA.

      T60 used as to create the smallest discontinuity possible when skipping down to T49 in order to ensure light foregrounds.

      Since `tertiaryContainer` in dark monochrome scheme requires a tone of 60, it should not be adjusted. Therefore, 60 is excluded here.

    • toneAllowsLightForeground

      public static boolean toneAllowsLightForeground(double tone)
      Tones less than ~T50 always permit white at 4.5 contrast.