From a5196d3a2386bd92384fe2c57d02efbcddf75cbc Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 23 Jan 2026 16:27:05 +0100 Subject: [PATCH 1/3] add swatch from single color --- .../lib/config/theme_configuration.dart | 5 ++ .../stream_color_swatch_helper.dart | 70 +++++++++++++++++++ .../src/theme/primitives/stream_colors.dart | 6 ++ .../theme/semantics/stream_color_scheme.dart | 6 +- .../stream_color_scheme.g.theme.dart | 2 +- 5 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart diff --git a/apps/design_system_gallery/lib/config/theme_configuration.dart b/apps/design_system_gallery/lib/config/theme_configuration.dart index ddcec78..a2564b8 100644 --- a/apps/design_system_gallery/lib/config/theme_configuration.dart +++ b/apps/design_system_gallery/lib/config/theme_configuration.dart @@ -272,6 +272,7 @@ class ThemeConfiguration extends ChangeNotifier { } void resetToDefaults() { + _brandPrimaryColor = null; // Accent _accentPrimary = null; _accentSuccess = null; @@ -332,6 +333,10 @@ class ThemeConfiguration extends ChangeNotifier { final effectiveAccentPrimary = _accentPrimary ?? _brandPrimaryColor; final colorScheme = baseColorScheme.copyWith( + // Brand + brand: _brandPrimaryColor == null + ? null + : StreamColorSwatch.fromColor(_brandPrimaryColor ?? StreamColors.blue.shade500), // Accent - brand primary affects accentPrimary accentPrimary: effectiveAccentPrimary, accentSuccess: _accentSuccess, diff --git a/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart b/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart new file mode 100644 index 0000000..07cbe7d --- /dev/null +++ b/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; + +import 'package:flutter/painting.dart'; + +class StreamColorSwatchHelper { + const StreamColorSwatchHelper._(); + + /// Generates a map of color shades based on the provided base colors. + /// + /// This internal method creates the shade variations using HSL color space + /// for more natural color transitions. The center shade (500) uses the original + /// color's lightness, and other shades are calculated proportionally. + static Map generateShadeMap(Color baseColor) { + final hslBase = HSLColor.fromColor(baseColor); + final centerLightness = hslBase.lightness; + print('lightness: $centerLightness'); + + return { + 50: _adjustLightness(hslBase, _calculateLightness(50, centerLightness)), + 100: _adjustLightness(hslBase, _calculateLightness(100, centerLightness)), + 150: _adjustLightness(hslBase, _calculateLightness(150, centerLightness)), + 200: _adjustLightness(hslBase, _calculateLightness(200, centerLightness)), + 300: _adjustLightness(hslBase, _calculateLightness(300, centerLightness)), + 400: _adjustLightness(hslBase, _calculateLightness(400, centerLightness)), + 501: _adjustLightness(hslBase, _calculateLightness(500, centerLightness)), + 600: _adjustLightness(hslBase, _calculateLightness(600, centerLightness)), + 700: _adjustLightness(hslBase, _calculateLightness(700, centerLightness)), + 800: _adjustLightness(hslBase, _calculateLightness(800, centerLightness)), + 900: _adjustLightness(hslBase, _calculateLightness(900, centerLightness)), + }; + } + + /// Calculates the target lightness for a given shade number based on the center lightness. + /// + /// The formula maps shade numbers (50-900) to lightness values where: + /// - 50 is the lightest (0.95) + /// - 500 uses the center lightness (original color's lightness) + /// - 900 is the darkest (0.12) + /// + /// For shades lighter than 500: lightness increases proportionally from center to 0.95 + /// For shades darker than 500: lightness decreases proportionally from center to 0.12 + static double _calculateLightness(int shade, double centerLightness) { + const minLightness = 0.12; // Darkest shade (900) + const maxLightness = 0.95; // Lightest shade (50) + const centerShade = 500; + + if (shade == centerShade) { + return centerLightness; + } + + if (shade < centerShade) { + // Lighter shades: interpolate between centerLightness and maxLightness + // Map shade from [50, 500) to lightness [maxLightness, centerLightness) + final t = (shade - 50) / (centerShade - 50); + return maxLightness - (maxLightness - centerLightness) * t; + } else { + // Darker shades: interpolate between centerLightness and minLightness + // Map shade from (500, 900] to lightness (centerLightness, minLightness] + final t = (shade - centerShade) / (900 - centerShade); + return centerLightness - (centerLightness - minLightness) * t; + } + } + + /// Adjusts the lightness of an HSL color while maintaining its hue and saturation. + /// + /// [lightness] should be between 0.0 and 1.0. + static Color _adjustLightness(HSLColor hslColor, double lightness) { + return hslColor.withLightness(lightness.clamp(0.0, 1.0)).toColor(); + } +} diff --git a/packages/stream_core_flutter/lib/src/theme/primitives/stream_colors.dart b/packages/stream_core_flutter/lib/src/theme/primitives/stream_colors.dart index 5c73dd5..b0d9344 100644 --- a/packages/stream_core_flutter/lib/src/theme/primitives/stream_colors.dart +++ b/packages/stream_core_flutter/lib/src/theme/primitives/stream_colors.dart @@ -1,6 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; +import 'stream_color_swatch_helper.dart'; + /// [Color] and [ColorSwatch] constants for the Stream design system. /// /// Most swatches have colors from 50 to 950. The smaller the number, the more @@ -226,6 +228,10 @@ abstract final class StreamColors { class StreamColorSwatch extends ColorSwatch { const StreamColorSwatch(super.primary, super._swatch); + factory StreamColorSwatch.fromColor(Color color) { + return StreamColorSwatch(color.toARGB32(), StreamColorSwatchHelper.generateShadeMap(color)); + } + /// The lightest shade. Color get shade50 => this[50]!; diff --git a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart index 537e364..bb68b17 100644 --- a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart +++ b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart @@ -43,7 +43,7 @@ class StreamColorScheme with _$StreamColorScheme { /// Creates a light color scheme. factory StreamColorScheme.light({ // Brand - StreamBrandColor? brand, + StreamColorSwatch? brand, // Accent Color? accentPrimary, Color? accentSuccess, @@ -215,7 +215,7 @@ class StreamColorScheme with _$StreamColorScheme { /// Creates a dark color scheme. factory StreamColorScheme.dark({ // Brand - StreamBrandColor? brand, + StreamColorSwatch? brand, // Accent Color? accentPrimary, Color? accentSuccess, @@ -437,7 +437,7 @@ class StreamColorScheme with _$StreamColorScheme { // ---- Brand ---- /// The brand color swatch with shades from 50 to 950. - final StreamBrandColor brand; + final StreamColorSwatch brand; // ---- Accent colors ---- diff --git a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.g.theme.dart b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.g.theme.dart index 6193d24..e690cea 100644 --- a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.g.theme.dart +++ b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.g.theme.dart @@ -97,7 +97,7 @@ mixin _$StreamColorScheme { } StreamColorScheme copyWith({ - StreamBrandColor? brand, + StreamColorSwatch? brand, Color? accentPrimary, Color? accentSuccess, Color? accentWarning, From 93888807e04df3ed6b80401c06b206a87c97a0c4 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 23 Jan 2026 16:38:40 +0100 Subject: [PATCH 2/3] remove print statement --- .../lib/src/theme/primitives/stream_color_swatch_helper.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart b/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart index 07cbe7d..ac0dc4c 100644 --- a/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart +++ b/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart @@ -13,7 +13,6 @@ class StreamColorSwatchHelper { static Map generateShadeMap(Color baseColor) { final hslBase = HSLColor.fromColor(baseColor); final centerLightness = hslBase.lightness; - print('lightness: $centerLightness'); return { 50: _adjustLightness(hslBase, _calculateLightness(50, centerLightness)), From 8864515ebc0d322873733de749f45b67ab5dd071 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 23 Jan 2026 16:42:02 +0100 Subject: [PATCH 3/3] remove unused import --- .../lib/src/theme/primitives/stream_color_swatch_helper.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart b/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart index ac0dc4c..9dc5fda 100644 --- a/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart +++ b/packages/stream_core_flutter/lib/src/theme/primitives/stream_color_swatch_helper.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:flutter/painting.dart'; class StreamColorSwatchHelper {