This is an automated email from the ASF dual-hosted git repository.

gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git


The following commit(s) were added to refs/heads/develop by this push:
     new 9dba5b593e Tidy ups, plus trying to get color variation working more 
perceptually for use in skinning.
9dba5b593e is described below

commit 9dba5b593e9f09efd272b7c343288f8bd3042617
Author: greg-dove <[email protected]>
AuthorDate: Tue Mar 24 17:59:15 2026 +1300

    Tidy ups, plus trying to get color variation working more perceptually for 
use in skinning.
---
 .../org/apache/royale/style/colors/CSSColor.as     | 335 ++++++++++++++++++++-
 .../org/apache/royale/style/colors/ColorSwatch.as  | 127 ++------
 .../apache/royale/style/colors/ThemeColorSet.as    | 155 +++++++---
 .../org/apache/royale/style/skins/CheckBoxSkin.as  |  26 +-
 .../royale/style/stylebeads/StyleBeadBase.as       |   2 +-
 .../org/apache/royale/style/util/StyleTheme.as     |  30 +-
 6 files changed, 505 insertions(+), 170 deletions(-)

diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/CSSColor.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/CSSColor.as
index 826e5e594b..0698f3af04 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/CSSColor.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/CSSColor.as
@@ -19,6 +19,7 @@
 package org.apache.royale.style.colors
 {
        import org.apache.royale.debugging.assert;
+       import org.apache.royale.style.colors.CSSColor;
        import org.apache.royale.utils.number.pinValue;
 
        public class CSSColor
@@ -29,7 +30,6 @@ package org.apache.royale.style.colors
                }
                public static function getColor(values:Array, opacity:Number = 
100, space:String = "rgb"):String{
                        assert(values && values.length == 3, "invalid color 
values");
-
                        var withAlpha:Boolean = opacity < 100;
                        var alphaString:String = opacity + "%";
                        var channels:String = values.join(" ");
@@ -55,14 +55,22 @@ package org.apache.royale.style.colors
                 * Returns an RGB array on a white -> base -> black ramp.
                 * 0 is white, 50 is the input color, 100 is black.
                 */
-               public static function getVariation(color:uint, 
grayValue:Number):Array
+               public static function getVariation(color:uint, 
grayValue:Number, darkMode:Boolean = false):Array
                {
                        var r:Number = (color >> 16) & 0xFF;
                        var g:Number = (color >> 8) & 0xFF;
                        var b:Number = color & 0xFF;
 
-                       var t:Number = pinValue(grayValue, 0, 100);
-                       var outR:Number;
+                       //convert to 0 - 1000 range
+                       var t:Number = pinValue(grayValue, 0, 100) * 10;
+                       
+                       //pass through lch color space for shading
+                       var lch:Array = rgb_ToOKLCH([r,g,b]);
+                       //shade it
+                       lch = 
lchShade(lch,factorForShadeTableInterpolated(t,darkMode));
+                       return oklch_ToRGB(lch);
+                       
+                       /*var outR:Number;
                        var outG:Number;
                        var outB:Number;
 
@@ -81,7 +89,7 @@ package org.apache.royale.style.colors
                                outB = b * (1 - toBlack);
                        }
 
-                       return [Math.round(outR), Math.round(outG), 
Math.round(outB)];
+                       return [Math.round(outR), Math.round(outG), 
Math.round(outB)];*/
                }
 
                /**
@@ -95,5 +103,322 @@ package org.apache.royale.style.colors
                        var color:uint = (rr << 16) | (gg << 8) | bb;
                        return getVariation(color, grayValue);
                }
+               
+               /**
+                * convert rgb to oklch format
+                * @param rgb Array of rgb values in 3 element array
+                * @return array of lch values
+                */
+               public static function rgb_ToOKLCH(rgb:Array):Array {
+                       var r:uint = rgb[0];
+                       var g:uint = rgb[1];
+                       var b:uint = rgb[2];
+                       //Math.cbrt;
+                       const cube_root:Function = Math['cbrt'] as Function; 
//not yet in Royale js typedefs
+                       // Normalize
+                       var R:Number = r / 255;
+                       var G:Number = g / 255;
+                       var B:Number = b / 255;
+                       
+                       // Convert to linear
+                       R = srgbToLinear(R);
+                       G = srgbToLinear(G);
+                       B = srgbToLinear(B);
+                       
+                       // Convert to OKLab
+                       var l:Number = 0.4122214708 * R + 0.5363325363 * G + 
0.0514459929 * B;
+                       var m:Number = 0.2119034982 * R + 0.6806995451 * G + 
0.1073969566 * B;
+                       var s:Number = 0.0883024619 * R + 0.2817188376 * G + 
0.6299787005 * B;
+                       
+                       var l_:Number = cube_root(l);
+                       var m_2:Number = cube_root(m);
+                       var s_2:Number = cube_root(s);
+                       
+                       var L:Number = 0.2104542553 * l_ + 0.7936177850 * m_2 - 
0.0040720468 * s_2;
+                       var a:Number = 1.9779984951 * l_ - 2.4285922050 * m_2 + 
0.4505937099 * s_2;
+                       var b2:Number = 0.0259040371 * l_ + 0.7827717662 * m_2 
- 0.8086757660 * s_2;
+                       
+                       var C:Number = Math.sqrt(a * a + b2 * b2);
+                       var H:Number = (Math.atan2(b2, a) * 180 / Math.PI + 
360) % 360;
+                       
+                       return  [L, C, H];
+               }
+               
+               /**
+                * convert from lch to rgb
+                * @param lch lch values in 3 element array
+                * @return rgb values in 3 element array
+                */
+               public static function oklch_ToRGB(lch:Array):Array {
+                       
+                       // --- 1. OKLCH → OKLab ---
+                       const L:Number = lch[0];
+                       const C:Number = lch[1];
+                       const hRad:Number = lch[2] * Math.PI / 180.0;
+                       
+                       const a_:Number = C * Math.cos(hRad);
+                       const b_:Number = C * Math.sin(hRad);
+                       
+                       // --- 2. OKLab → LMS (non-linear) ---
+                       const l_:Number = L + 0.3963377774 * a_ + 0.2158037573 
* b_;
+                       const m_:Number = L - 0.1055613458 * a_ - 0.0638541728 
* b_;
+                       const s_:Number = L - 0.0894841775 * a_ - 1.2914855480 
* b_;
+                       
+                       // cube them (inverse of cbrt)
+                       const l:Number = l_ * l_ * l_;
+                       const m:Number = m_ * m_ * m_;
+                       const s:Number = s_ * s_ * s_;
+                       
+                       // --- 3. LMS → linear RGB ---
+                       var rLin:Number =
+                                       + 4.0767416621 * l
+                                       - 3.3077115913 * m
+                                       + 0.2309699292 * s;
+                       
+                       var gLin:Number =
+                                       - 1.2684380046 * l
+                                       + 2.6097574011 * m
+                                       - 0.3413193965 * s;
+                       
+                       var bLin:Number =
+                                       - 0.0041960863 * l
+                                       - 0.7034186147 * m
+                                       + 1.7076147010 * s;
+                       
+                       // --- 4. linear RGB → sRGB clamped ---
+                       var r:uint = uint(pinValue(linearToSrgb(rLin),0,1) * 
255);
+                       var g:uint = uint(pinValue(linearToSrgb(gLin),0,1) * 
255);
+                       var b:uint = uint(pinValue(linearToSrgb(bLin),0,1) * 
255);
+                       
+                       return [r ,g ,b];
+               }
+               
+               private static function srgbToLinear(x:Number):Number {
+                       return (x <= 0.04045) ? x / 12.92 : Math.pow((x + 
0.055) / 1.055, 2.4);
+               }
+               
+               private static function linearToSrgb(x:Number):Number {
+                       return (x <= 0.0031308) ? 12.92 * x     : 1.055 * 
Math.pow(x, 1.0 / 2.4) - 0.055;
+               }
+               
+               /*private static function lerp(a:Number, b:Number, 
t:Number):Number {
+                       return a + (b - a) * t;
+               }*/
+               
+               public static function lchShade(base:Array, factor:Number):Array
+               {
+                       const baseL:Number = base[0];
+                       const baseC:Number = base[1];
+                       const baseH:Number = base[2];
+                       
+                       // Your table ranges roughly 0.45–1.60.
+                       // factor > 1  → lighter than base
+                       // factor < 1  → darker than base
+                       
+                       var newL:Number;
+                       var newC:Number;
+                       
+                       if (factor >= 1.0) {
+                               // LIGHTER SIDE (50–400)
+                               // Normalize factor so:
+                               //   factor = 1.0 → t = 0 (base)
+                               //   factor = 1.6 → t = 1 (lightest)
+                               var tLight:Number = (factor - 1.0) / (1.6 - 
1.0);
+                               if (tLight < 0) tLight = 0;
+                               if (tLight > 1) tLight = 1;
+                               
+                               // Move L toward a very light target (~0.97)
+                               newL = baseL + (0.97 - baseL) * tLight;
+                               
+                               // Reduce chroma as we get lighter
+                               //  t = 0 → baseC
+                               //  t = 1 → ~30% of baseC
+                               newC = baseC * (1.0 - 0.7 * tLight);
+                       } else {
+                               // DARKER SIDE (600–900)
+                               // Normalize factor so:
+                               //   factor = 1.0 → t = 0 (base)
+                               //   factor = 0.45 → t = 1 (darkest)
+                               var tDark:Number = (1.0 - factor) / (1.0 - 
0.45);
+                               if (tDark < 0) tDark = 0;
+                               if (tDark > 1) tDark = 1;
+                               
+                               // Move L toward a dark target (~0.12)
+                               newL = baseL + (0.12 - baseL) * tDark;
+                               
+                               // Slightly increase chroma as we get darker
+                               //  t = 0 → baseC
+                               //  t = 1 → ~120% of baseC
+                               newC = baseC * (1.0 + 0.2 * tDark);
+                       }
+                       
+                       return [
+                               pinValue(newL, 0, 1),
+                               pinValue(newC, 0, 0.4),
+                               baseH
+                       ];
+               }
+               
+               private static const shading_factors:Object = {
+                       50: 1.80,
+                       100: 1.60,
+                       200: 1.40,
+                       300: 1.20,
+                       400: 1.08,
+                       500: 1.00,
+                       600: 0.90,
+                       700: 0.75,
+                       800: 0.60,
+                       900: 0.45
+               }
+               
+               private static var inverted_factors:Object;
+                               
+               private static const SHADE_KEYS:Array = [];
+               private static const INVERTED_SHADE_KEYS:Array = [];
+               
+               COMPILE::JS
+               private static const lookups:Map = new Map();
+               COMPILE::SWF
+               private static const lookups:Object = {};
+       
+               private static function 
factorForShadeTableInterpolated(shade:uint, darkMode:Boolean):Number {
+                       assert(shade>=0 && shade<=1000, 'bad parameter')
+                       if (darkMode && !inverted_factors) {
+                               inverted_factors = invertTable(shading_factors);
+                               trace('inverted', inverted_factors);
+                       }
+                       const factors:Object = darkMode ? inverted_factors : 
shading_factors;
+                       const shadeKeys:Array = darkMode ? 
CSSColor.INVERTED_SHADE_KEYS : CSSColor.SHADE_KEYS;
+                       if (!shadeKeys.length) {
+                               //populate it first time
+                               COMPILE::JS{
+                                       var keys:Array = 
Object.keys(factors).map(function(k:String):int { return uint(k); });
+                               }
+                               COMPILE::SWF{
+                                       var keys:Array = [];
+                                       for (var key:String in factors) 
keys.push(key);
+                                       keys = keys.map(function(k:String):int 
{ return uint(k); });
+                               }
+                               
+                               keys.sort(Array.NUMERIC);
+                               shadeKeys.push.apply(shadeKeys, keys);
+                       }
+                       
+                       // clamp to valid range
+                       if (shade <= 50) return factors[50];
+                       if (shade >= 900) return factors[900];
+                       
+                       // exact match
+                       if (factors[shade] != null)
+                               return factors[shade];
+
+                       var resultMap:Object;
+                       var result:Number;
+                       COMPILE::JS {
+                               resultMap = lookups.get(shade);
+                               if (!resultMap) {
+                                       resultMap = { dark:NaN,light:NaN};
+                                       lookups.set(shade, resultMap);
+                               }
+                       }
+                       COMPILE::SWF {
+                               resultMap = lookups[shade];
+                               if (!resultMap) {
+                                       resultMap = { dark:NaN,light:NaN};
+                                       lookups[shade] = resultMap;
+                               }
+                       }
+                       result = darkMode ? resultMap.dark : resultMap.light;
+                       if (isNaN(result)) {
+                               // find neighbors
+                               var lower:int = 50;
+                               var upper:int = 900;
+                               
+                               for (var i:int = 0; i < shadeKeys.length - 1; 
i++) {
+                                       var a:int = shadeKeys[i];
+                                       var b:int = shadeKeys[i+1];
+                                       
+                                       if (shade > a && shade < b) {
+                                               lower = a;
+                                               upper = b;
+                                               break;
+                                       }
+                               }
+                               
+                               var f1:Number = factors[lower];
+                               var f2:Number = factors[upper];
+                               
+                               var t:Number = (shade - lower) / (upper - 
lower);
+                               result = f1 + t * (f2 - f1);
+                               
+                               if (darkMode) {
+                                       resultMap.dark = result;
+                               } else {
+                                       resultMap.light = result;
+                               }
+                       }
+                       return result;
+               }
+               
+               
+               private static function invertTable(table:Object):Object {
+                       COMPILE::JS{
+                               const keys:Array = 
Object.keys(table).sort(Array.NUMERIC);
+                       }
+                       COMPILE::SWF{
+                               var keys:Array = [];
+                               for (var key:String in table) keys.push(key);
+                               keys = keys.sort(Array.NUMERIC);
+                       }
+                       
+                       const values:Array = 
keys.map(function(key:String):Number{return table[key]}).reverse();
+                       
+                       const inverted:Object = {};
+                       for (var i:int = 0; i < keys.length; i++) {
+                               inverted[keys[i]] = values[i];
+                       }
+                       return inverted;
+               }
+               
+               
+               /*public static function testRoundTrip():void {
+                       
+                       const tests:Array = [
+                               0x000000, 0xFFFFFF,
+                               0xFF0000, 0x00FF00, 0x0000FF,
+                               0xFFFF00, 0xFF00FF, 0x00FFFF,
+                               0x808080, 0xC0C0C0, 0x404040
+                       ];
+                       
+                       // add random colors
+                       for (var i:int = 0; i < 20; i++) {
+                               tests.push(Math.random() * 0xFFFFFF);
+                       }
+                       
+                       for each (var rgb:uint in tests) {
+                               var r1:uint = (rgb >> 16) & 0xFF;
+                               var g1:uint = (rgb >> 8) & 0xFF;
+                               var b1:uint = rgb & 0xFF;
+                               var oklch:Array = rgbToOKLCH([r1,g1,b1]);
+                               var rgb2:Array = oklchToRGB(oklch);
+                               
+                               var r2:uint = rgb2[0];
+                               var g2:uint = rgb2[1];
+                               var b2:uint = rgb2[2];
+                               
+                               var rgbOut:uint = r2<<16 | g2<<8 | b2;
+                               
+                               var dr:int = r2 - r1;
+                               var dg:int = g2 - g1;
+                               var db:int = b2 - b1;
+                               
+                               trace(
+                                               "RGB:", rgb.toString(16),
+                                               "→", rgbOut.toString(16),
+                                               "Δ:", dr, dg, db
+                               );
+                       }
+               }*/
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ColorSwatch.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ColorSwatch.as
index bbb541a03d..183f00e531 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ColorSwatch.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ColorSwatch.as
@@ -19,6 +19,7 @@
 package org.apache.royale.style.colors
 {
        import org.apache.royale.debugging.assert;
+       import org.apache.royale.style.elements.Col;
        import org.apache.royale.style.util.CSSLookup;
        import org.apache.royale.utils.CSSUtils;
 
@@ -73,7 +74,7 @@ package org.apache.royale.style.colors
                        "red": 0xFB2C36,
                        "rose": 0xFF2056,
                        "sky": 0x00A6F4,
-                       "slate": 0x62748E,
+                       "slate": 0x64748B,
                        "stone": 0x79716B,
                        "taupe": 0x7C6D67,
                        "teal": 0x00BBA7,
@@ -81,29 +82,28 @@ package org.apache.royale.style.colors
                        "yellow": 0xF0B100,
                        "zinc": 0x71717B
                };
-
+               
+               private static const exceptions:Array = [
+                       "transparent",
+                       "currentColor",
+                       "inherit",
+                       "none",
+                       "black",
+                       "white"
+               ]
+       
                /**
                 * Subclasses must specify colorBase before calling this 
constructor.
                 */
-               public function 
ColorSwatch(swatch:String,shade:Number,opacity:Number = 100)
+               public function 
ColorSwatch(swatch:String,shade:Number,opacity:Number = 
100,darkMode:Boolean=false)
                {
                        var base:Object = BASE_COLORS[swatch] || 
CSSLookup.getProperty(swatch);
                        assert(base, "Invalid color swatch: " + swatch);
-                       
+                       assert(shade>=0 && shade<=1000, "Invalid shade: " + 
shade);
                        var baseColor:uint = CSSUtils.toColor(base);
-                       var rgbComponents:Array= [(baseColor & 
0xff0000)>>16,(baseColor & 0xff00)>>8,(baseColor & 0xff)];
-                       var lch:Array = 
rgbToOKLCH(rgbComponents[0],rgbComponents[1],rgbComponents[2]);
-                       
                        // Convert from 50,100,200... to 5,10,20... for easier 
math.
-                       
-                       
-                       
                //      shade = Math.round(shade/10);
-               //      var colorVals:Array = 
CSSColor.getVariation(CSSUtils.toColor(base),shade);
-                       
-                       var colorVals:Array = 
lchShade(lch,factorForShade(shade));
-                       colorSpace = 'oklch';
-
+                       var colorVals:Array = 
CSSColor.getVariation(baseColor,Math.round(shade/10),darkMode);
                        assert(opacity >= 0 && opacity <= 100, "Opacity must be 
between 0 and 100");
                        colorBase = swatch;
                        colorShade = shade;
@@ -114,7 +114,7 @@ package org.apache.royale.style.colors
                                colorSpecifier += "/" + opacity;
                        }
                        colorValue = CSSColor.getColor(colorVals, opacity, 
colorSpace);
-
+                       dark = darkMode;
                        CSSLookup.register (colorSpecifier,colorValue);
                }
                public var colorBase:String;
@@ -123,7 +123,7 @@ package org.apache.royale.style.colors
                public var colorValue:String;
                public var colorSpace:String = "rgb";
                public var colorSpecifier:String;
-
+               public var dark:Boolean;
                
                /**
                 * create a ColorSwatch variant from this instance
@@ -134,7 +134,7 @@ package org.apache.royale.style.colors
                public function getVariant(alternateShade:Number, 
alternateOpacity:Number = NaN):ColorSwatch{
                        if (isNaN(alternateShade)) alternateShade = colorShade;
                        if (isNaN(alternateOpacity)) alternateOpacity = 
colorOpacity;
-                       var alternate:ColorSwatch = new 
ColorSwatch(colorBase,alternateShade,alternateOpacity);
+                       var alternate:ColorSwatch = new 
ColorSwatch(colorBase,alternateShade,alternateOpacity,dark);
                        assert(alternate.colorShade != colorShade || 
alternate.colorOpacity != colorOpacity, "parameters not configured to create a 
variant");
                        return alternate;
                }
@@ -143,7 +143,7 @@ package org.apache.royale.style.colors
                        return colorSpecifier;
                }
                
-               public static function 
fromSpecifier(specifier:String):ColorSwatch
+               public static function 
fromSpecifier(specifier:String,darkMode:Boolean=false):ColorSwatch
                {
                        var parts:Array = specifier.split("-");
                        assert(parts.length == 2, "Invalid color specifier: " + 
specifier);
@@ -152,94 +152,19 @@ package org.apache.royale.style.colors
                        var shadeParts:Array = shadeAndOpacity.split("/");
                        var shade:Number = Number(shadeParts[0]);
                        var opacity:Number = shadeParts.length > 1 ? 
Number(shadeParts[1]) : 100;
-                       return new ColorSwatch(base, shade, opacity);
+                       return new ColorSwatch(base, shade, opacity, darkMode);
                }
                
-               public static function rgbToOKLCH(r:int, g:int, b:int):Array {
-                       // Normalize
-                       var R:Number = r / 255;
-                       var G:Number = g / 255;
-                       var B:Number = b / 255;
-                       
-                       // Convert to linear
-                       R = srgbToLinear(R);
-                       G = srgbToLinear(G);
-                       B = srgbToLinear(B);
-                       
-                       // Convert to OKLab
-                       var l:Number = 0.4122214708 * R + 0.5363325363 * G + 
0.0514459929 * B;
-                       var m:Number = 0.2119034982 * R + 0.6806995451 * G + 
0.1073969566 * B;
-                       var s:Number = 0.0883024619 * R + 0.2817188376 * G + 
0.6299787005 * B;
-                       
-                       var l_:Number = Math['cbrt'](l);
-                       var m_2:Number = Math['cbrt'](m);
-                       var s_2:Number = Math['cbrt'](s);
-                       
-                       var L:Number = 0.2104542553 * l_ + 0.7936177850 * m_2 - 
0.0040720468 * s_2;
-                       var a:Number = 1.9779984951 * l_ - 2.4285922050 * m_2 + 
0.4505937099 * s_2;
-                       var b2:Number = 0.0259040371 * l_ + 0.7827717662 * m_2 
- 0.8086757660 * s_2;
-                       
-                       var C:Number = Math.sqrt(a * a + b2 * b2);
-                       var H:Number = (Math.atan2(b2, a) * 180 / Math.PI + 
360) % 360;
-                       
-                       return  [L, C, H];
-               }
-               private static function srgbToLinear(x:Number):Number {
-                       return (x <= 0.04045) ? x / 12.92 : Math.pow((x + 
0.055) / 1.055, 2.4);
+               public static function isColorName(name:String):Boolean{
+                       return name in BASE_COLORS;
                }
                
-               private static const factors:Object = {
-                       50: 1.60,
-                       100: 1.45,
-                       200: 1.30,
-                       300: 1.15,
-                       400: 1.05,
-                       500: 1.00,
-                       600: 0.90,
-                       700: 0.75,
-                       800: 0.60,
-                       900: 0.45
+               public static function getColorValue(name:String):Boolean{
+                       return BASE_COLORS[name];
                }
-               public static function lchShade(base:Array, 
factor:Number):Array {
-                       return [
-                                       base[0] * factor,                 // 
adjust lightness
-                                       base[1] * (0.5 + factor / 2),     // 
adjust chroma
-                                       base[2]                           // 
keep hue constant
-                       ];
-               }
-               private static const SHADE_KEYS:Array = 
[50,100,200,300,400,500,600,700,800,900];
                
-               public static function factorForShade(shade:int):Number {
-                       
-                       // clamp to valid range
-                       if (shade <= 50) return factors[50];
-                       if (shade >= 900) return factors[900];
-                       
-                       // exact match
-                       if (factors[shade] != null)
-                               return factors[shade];
-                       
-                       // find neighbors
-                       var lower:int = 50;
-                       var upper:int = 900;
-                       
-                       for (var i:int = 0; i < SHADE_KEYS.length - 1; i++) {
-                               var a:int = SHADE_KEYS[i];
-                               var b:int = SHADE_KEYS[i+1];
-                               
-                               if (shade > a && shade < b) {
-                                       lower = a;
-                                       upper = b;
-                                       break;
-                               }
-                       }
-                       
-                       var f1:Number = factors[lower];
-                       var f2:Number = factors[upper];
-                       
-                       var t:Number = (shade - lower) / (upper - lower);
-                       
-                       return f1 + t * (f2 - f1);
+               public static function isExceptionValue(value:String):Boolean{
+                       return exceptions.indexOf(value) != -1;
                }
                
        }
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ThemeColorSet.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ThemeColorSet.as
index d605c8d2c0..467bda9287 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ThemeColorSet.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ThemeColorSet.as
@@ -36,15 +36,6 @@ package org.apache.royale.style.colors
                public static const ERROR:String = 'error';
                public static const NEUTRAL:String = 'neutral';
                
-               public static const BASE_CONTENT:String        = "base-content";
-               public static const PRIMARY_CONTENT:String     = 
"primary-content";
-               public static const SECONDARY_CONTENT:String   = 
"secondary-content";
-               public static const ACCENT_CONTENT:String      = 
"accent-content";
-               public static const INFO_CONTENT:String        = "info-content";
-               public static const SUCCESS_CONTENT:String     = 
"success-content";
-               public static const WARNING_CONTENT:String     = 
"warning-content";
-               public static const ERROR_CONTENT:String       = 
"error-content";
-               public static const NEUTRAL_CONTENT:String     = 
"neutral-content";
                
                
                private static const _fieldNames:Array = [
@@ -56,16 +47,7 @@ package org.apache.royale.style.colors
                        SUCCESS,
                        WARNING,
                        ERROR,
-                       NEUTRAL,
-                       BASE_CONTENT,
-                       PRIMARY_CONTENT,
-                       SECONDARY_CONTENT,
-                       ACCENT_CONTENT,
-                       NEUTRAL_CONTENT,
-                       INFO_CONTENT,
-                       SUCCESS_CONTENT,
-                       WARNING_CONTENT,
-                       ERROR_CONTENT
+                       NEUTRAL
                ]
                
                public static function get validFieldNames():Array{
@@ -87,17 +69,10 @@ package org.apache.royale.style.colors
                        assert(_fieldNames.indexOf(key) != -1, 'unknown key 
"'+key+'" - must be one of :"'+_fieldNames.join('","')+'"')
                        if (value) {
                                // do we need to validate value?
-                               const exceptions:Array = [      
-                                       "transparent",
-                                       "currentColor",
-                                       "inherit",
-                                       "none",
-                                       "black",
-                                       "white"
-                               ]
-                               var valueToSet:Object = 
exceptions.indexOf(value) == -1 ? ColorSwatch.fromSpecifier(value) : value;
+                               assert(ColorSwatch.isExceptionValue(value) || 
ColorSwatch.isColorName(value), 'unsupported base color:'+value)
+                       //      var valueToSet:Object = 
exceptions.indexOf(value) == -1 ? ColorSwatch.fromSpecifier(value) : value;
                                COMPILE::JS {
-                                       storage.set(key,valueToSet);
+                                       storage.set(key,value);
                                }
                        } else {
                                COMPILE::JS {
@@ -106,13 +81,13 @@ package org.apache.royale.style.colors
                        }
                }
                
-               public function getThemeColorSwatch(key:String):ColorSwatch{
+               public function getThemeBaseColor(key:String):String{
                        assert(_fieldNames.indexOf(key) != -1, 'unknown key 
"'+key+'" - must be one of :"'+_fieldNames.join('","')+'"');
                        COMPILE::JS{
                                //Q: should there always be a neutral default 
if no lookup is registered for a specific set?
                                if (!storage.has(key)) {
                                        //do something?
-                                       
storage.set(key,ColorSwatch.fromSpecifier(ColorSwatch.NEUTRAL+'-500'/*, key*/));
+                                       storage.set(key,ColorSwatch.NEUTRAL);
                                }
                                return storage.get(key)
                        }
@@ -120,11 +95,121 @@ package org.apache.royale.style.colors
                                return null;
                        }
                }
+               COMPILE::JS
+               private var swatchStore:Map = new Map();
+               COMPILE::SWF
+               private var swatchStore:Object = {};
+               
+               public function 
getSwatch(key:String,shade:Number=500,opacity:Number=100,dark:Boolean=false):ColorSwatch{
+                       const lookupVal:String = getThemeBaseColor(key);
+                       assert(!ColorSwatch.isExceptionValue(lookupVal), 'no 
swatch or variation for '+key+":"+lookupVal);
+                       var specifier:String = lookupVal + "-" + shade + '/' + 
opacity;
+                       trace(key,specifier);
+                       var lookupKey:String = key +':'+ specifier;
+                       var swatch:ColorSwatch;
+                       var swatchStoreMap:Object;
+                       COMPILE::JS {
+                               swatchStoreMap = swatchStore.get(lookupKey);
+                               if (!swatchStoreMap) {
+                                       swatchStoreMap = {light:null,dark:null};
+                                       
swatchStore.set(lookupKey,swatchStoreMap);
+                               }
+                       }
+                       COMPILE::SWF {
+                               swatchStoreMap = swatchStore[lookupKey];
+                               if (!swatchStoreMap) {
+                                       swatchStoreMap = {light:null,dark:null};
+                                       swatchStore[lookupKey] = swatchStoreMap;
+                               }
+                       }
+                       swatch = dark ? swatchStoreMap.dark : 
swatchStoreMap.light;
+                       if (!swatch) {
+                               swatch = 
ColorSwatch.fromSpecifier(specifier,dark);
+                               if (dark) {
+                                       swatchStoreMap.dark = swatch;
+                               } else {
+                                       swatchStoreMap.light = swatch;
+                               }
+                       }
+                       trace(swatch);
+                       return swatch;
+               }
+               
+               private var _baseContent:String;
+               public function get baseContent():ColorSwatch{
+                       return ColorSwatch.fromSpecifier(_baseContent,false)
+               }
+               
+               private var _baseContentWeak:String;
+               public function get baseContentWeak():ColorSwatch{
+                       return ColorSwatch.fromSpecifier(_baseContentWeak,false)
+               }
+               
+               public function 
getContrastSwatch(original:ColorSwatch):ColorSwatch{
+                       var swatch:String = original.colorBase;
+                       var shade:Number = original.colorShade;
+                       var opacity:Number = original.colorOpacity;
+                       var dark:Boolean = original.dark;
+                       var nameVariant:String = swatch+'-contrast';
+                       if (!CSSLookup.has(nameVariant)) {
+                               
registerContrastVariant(nameVariant,swatch,shade,dark,false);
+                       }
+                       return new ColorSwatch(nameVariant,500,opacity,dark);
+               }
+               
+               public function 
getWeakContrastSwatch(original:ColorSwatch):ColorSwatch{
+                       var swatch:String = original.colorBase;
+                       var shade:Number = original.colorShade;
+                       var opacity:Number = original.colorOpacity;
+                       var dark:Boolean = original.dark;
+                       var nameVariant:String = swatch+'-contrast-weak';
+                       if (!CSSLookup.has(nameVariant)) {
+                               
registerContrastVariant(nameVariant,swatch,shade,dark,true);
+                       }
+                       return new ColorSwatch(nameVariant,500,opacity,dark);
+               }
+               
+               private static function 
registerContrastVariant(nameVariant:String, swatch:String, 
shade:Number,dark:Boolean, weak:Boolean):void{
+                       var base:Object = ColorSwatch.getColorValue(swatch) || 
CSSLookup.getProperty(swatch);
+                       var baseColor:uint = CSSUtils.toColor(base);
+                       // Convert from 50,100,200... to 5,10,20... for easier 
math.
+                       shade = Math.round(shade/10);
+                       var colorVals:Array = 
CSSColor.getVariation(baseColor,shade,dark);
+                       var oklch:Array = CSSColor.rgb_ToOKLCH(colorVals);
+                       var L:Number = oklch[0];
+                       var H:Number = oklch[2];
+                       var fg:Array;
+                       
+                       if (weak) {
+                               if (L < 0.55)
+                                       fg = [0.80, 0.01, H]; // weak light
+                               else
+                                       fg = [0.35, 0.02, H]; // weak dark
+                       } else {
+                               if (L < 0.55)
+                                       fg = [0.97, 0.02, H]; // light contrast
+                               else
+                                       fg = [0.18, 0.03, H]; // dark contrast
+                       }
+                       
+                       colorVals = CSSColor.oklch_ToRGB(fg);
+                       
CSSLookup.register(nameVariant,'rgb('+colorVals.join(',')+')');
+               }
                
                public function fromJSON(obj:Object):void{
                        if (typeof obj == 'string') obj = JSON.parse(obj as 
String);
                        for (var key:String in obj) {
-                               setThemeColor(key,obj[key]);
+                               switch(key) {
+                                       case '_baseContent':
+                                               _baseContent = obj[key];
+                                               break;
+                                       case '_baseContentWeak':
+                                               _baseContentWeak = obj[key];
+                                               break;
+                                       default:
+                                               setThemeColor(key,obj[key]);
+                               }
+                               
                        }
                }
                
@@ -133,9 +218,11 @@ package org.apache.royale.style.colors
                        COMPILE::JS{
                                var keys:Array = Object.keys(storage);
                                for each(var key:String in keys) {
-                                       var swatch:ColorSwatch = 
storage.get(key);
-                                       obj[key] = swatch.colorSpecifier;
+                                       var color:String = storage.get(key);
+                                       obj[key] = color;
                                }
+                               obj['_baseContent'] = _baseContent;
+                               obj['_baseContentWeak'] = _baseContentWeak;
                        }
                        return obj;
                }
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/CheckBoxSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/CheckBoxSkin.as
index f025a538c2..eb0faa8eaa 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/CheckBoxSkin.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/CheckBoxSkin.as
@@ -127,13 +127,15 @@ package org.apache.royale.style.skins
                                createBoxStyles();
                        return _boxStyles;
                }
+               
                private function createBoxStyles():void
                {
                        var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
-                       var primaryColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.PRIMARY);
-                       var enabledBorder:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.NEUTRAL);
-                       var disabledBorder:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.NEUTRAL).getVariant(300);
-                       var disabledFillColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.NEUTRAL).getVariant(100);
+                       var primaryColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.PRIMARY,500);
+                       var enabledBorder:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.NEUTRAL,500);
+                       var disabledBorder:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 300,50);
+                       var disabledFillColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 200, 50);
+                       
                        
                        var size:Number = 16 * getMultiplier();
                        var box:String = computeSize(size * 1.25, host.unit);
@@ -186,8 +188,8 @@ package org.apache.royale.style.skins
                        var size:Number = 16 * getMultiplier();
                        var fontSize:String = computeSize(size, host.unit);
                        var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
-                       var enabledColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.BASE_CONTENT);
-                       var disabledColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.NEUTRAL_CONTENT).getVariant(NaN, 60);
+                       var enabledColor:ColorSwatch = colorSet.baseContent;
+                       var disabledColor:ColorSwatch = 
colorSet.baseContentWeak;
                        
                        _labelStyles = [
                                new GridColumnStart("2"),
@@ -216,8 +218,10 @@ package org.apache.royale.style.skins
                {
                        if(!_checkIcon){
                                var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
-                               var enabledColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.PRIMARY_CONTENT);
-                               var disabledColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.NEUTRAL_CONTENT).getVariant(600, 40);
+                               var enabledColor:ColorSwatch = 
colorSet.getContrastSwatch(colorSet.getSwatch(ThemeColorSet.PRIMARY,500));
+                               //weak contrast against disabled fill:
+                               var disabledFillColor:ColorSwatch  = 
colorSet.getSwatch(ThemeColorSet.BASE, 200, 50);
+                               var disabledColor:ColorSwatch = 
colorSet.getWeakContrastSwatch(disabledFillColor);
                                
                                _checkIcon = new Div();
                                var size:Number = 16 * getMultiplier();
@@ -270,8 +274,10 @@ package org.apache.royale.style.skins
                {
                        if(!_indeterminateIcon){
                                var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
-                               var enabledColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.PRIMARY_CONTENT);
-                               var disabledColor:ColorSwatch = 
colorSet.getThemeColorSwatch(ThemeColorSet.NEUTRAL_CONTENT).getVariant(600, 40);
+                               var enabledColor:ColorSwatch = 
colorSet.getContrastSwatch(colorSet.getSwatch(ThemeColorSet.PRIMARY,500));
+                               var disabledFillColor:ColorSwatch  = 
colorSet.getSwatch(ThemeColorSet.BASE, 200, 50);
+                               var disabledColor:ColorSwatch = 
colorSet.getWeakContrastSwatch(disabledFillColor);
+                               
                                _indeterminateIcon = new Div();
                                var size:Number = 16 * getMultiplier();
 
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/StyleBeadBase.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/StyleBeadBase.as
index 6b63942b4d..75286da4c4 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/StyleBeadBase.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/StyleBeadBase.as
@@ -140,7 +140,7 @@ package org.apache.royale.style.stylebeads
                                                ruleVal = 
CSSLookup.getProperty(selectorVal);
                                        else
                                        {
-                                               var color:ColorSwatch = 
ColorSwatch.fromSpecifier(selectorVal);
+                                               var color:ColorSwatch = 
ColorSwatch.fromSpecifier(selectorVal,false);
                                                ruleVal = color.colorValue;
                                        }
                                        break;
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/util/StyleTheme.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/util/StyleTheme.as
index 03ee2bc44d..93021c0bb3 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/util/StyleTheme.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/util/StyleTheme.as
@@ -34,25 +34,17 @@ package org.apache.royale.style.util
                
                
                public var themeColorSet:ThemeColorSet = new ThemeColorSet({
-                       'primary': 'indigo-500',
-                       "primary-content": "indigo-50",
-                       'secondary': 'rose-500',
-                       "secondary-content": "rose-50",
-                       'accent': 'teal-400',
-                       "accent-content": "teal-800",
-                       'neutral': 'neutral-200',        // light neutral 
surface
-                       "neutral-content": "neutral-800", // readable dark 
text/icon on neutral
-                       'info': 'sky-400',
-                       "info-content": "blue-800",
-                       'success': 'emerald-400',
-                       "success-content": "emerald-800",
-                       'warning': 'amber-500',
-                       "warning-content": "amber-800",
-                       'error': 'red-500',
-                       "error-content": "red-800",
-                       "base": "slate-50",
-                       "base-content": "slate-900"
-
+                       'primary': 'blue',
+                       'secondary': 'rose',
+                       'accent': 'teal',
+                       'neutral': 'neutral',
+                       'info': 'sky',
+                       'success': 'emerald',
+                       'warning': 'amber',
+                       'error': 'red',
+                       "base": "slate",
+                       "_baseContent" : 'slate-500',
+                       "_baseContentWeak" : 'neutral-400/80'
                });
 
                public var spacing:Number = 4;

Reply via email to