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;