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

greg-dove 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 204195cac6 cumulative WIP on Toast and Color utils, and Icons. 
Resolving contrast colors within theme still needs some attention.
204195cac6 is described below

commit 204195cac6d4ba23ab80a8547ff9128f896d52a8
Author: greg-dove <[email protected]>
AuthorDate: Mon Apr 20 15:43:44 2026 +1200

    cumulative WIP on Toast and Color utils, and Icons. Resolving contrast 
colors within theme still needs some attention.
---
 .../projects/Style/src/main/resources/defaults.css |   3 +
 .../Style/src/main/resources/style-manifest.xml    |   9 +
 .../royale/org/apache/royale/style/Application.as  |   8 +
 .../royale/org/apache/royale/style/StyleUIBase.as  |   2 +-
 .../main/royale/org/apache/royale/style/Toast.as   | 304 ++++++++++++++++
 .../org/apache/royale/style/colors/CSSColor.as     | 369 --------------------
 .../org/apache/royale/style/colors/ColorSwatch.as  |  64 +++-
 .../style/colors/{CSSColor.as => ColorUtils.as}    | 251 ++++++++++++--
 .../apache/royale/style/colors/ThemeColorSet.as    |  96 ++++--
 .../org/apache/royale/style/elements/Textarea.as   |  82 +++++
 .../org/apache/royale/style/skins/CheckBoxSkin.as  |  11 +-
 .../layout/InsetBlock.as => skins/IToastSkin.as}   |  26 +-
 .../org/apache/royale/style/skins/ToastSkin.as     | 381 +++++++++++++++++++++
 .../royale/style/stylebeads/anim/Animation.as      |  16 +-
 .../InsetBlockEnd.as => anim/AnimationDuration.as} |  21 +-
 .../AnimationIterationCount.as}                    |  24 +-
 .../{Animation.as => AnimationTimingFunction.as}   |  86 ++---
 .../style/stylebeads/anim/CustomAnimation.as       | 105 ++++++
 .../{layout/InsetBlockEnd.as => anim/Keyframes.as} |  44 ++-
 .../royale/style/stylebeads/layout/Bottom.as       |   4 +-
 .../apache/royale/style/stylebeads/layout/Inset.as |   4 +-
 .../royale/style/stylebeads/layout/InsetBase.as    |   9 +-
 .../royale/style/stylebeads/layout/InsetBlock.as   |   4 +-
 .../style/stylebeads/layout/InsetBlockEnd.as       |   4 +-
 .../style/stylebeads/layout/InsetBlockStart.as     |   4 +-
 .../style/stylebeads/layout/InsetInlineEnd.as      |   4 +-
 .../style/stylebeads/layout/InsetInlineStart.as    |   4 +-
 .../apache/royale/style/stylebeads/layout/Left.as  |   4 +-
 .../apache/royale/style/stylebeads/layout/Right.as |   4 +-
 .../apache/royale/style/stylebeads/layout/Top.as   |   4 +-
 .../attribute/NotDataState.as}                     |  32 +-
 .../org/apache/royale/style/support/Icons.as       |  92 +++++
 32 files changed, 1508 insertions(+), 567 deletions(-)

diff --git a/frameworks/projects/Style/src/main/resources/defaults.css 
b/frameworks/projects/Style/src/main/resources/defaults.css
index d4b34cc9a9..2afbdea9b7 100644
--- a/frameworks/projects/Style/src/main/resources/defaults.css
+++ b/frameworks/projects/Style/src/main/resources/defaults.css
@@ -224,3 +224,6 @@ Tree
        IViewportModel: 
ClassReference("org.apache.royale.html.beads.models.ViewportModel");
 }
 
+Toast {
+       IStyleSkin: ClassReference("org.apache.royale.style.skins.ToastSkin");
+}
diff --git a/frameworks/projects/Style/src/main/resources/style-manifest.xml 
b/frameworks/projects/Style/src/main/resources/style-manifest.xml
index 7e3f6b0265..fc09f8cedd 100644
--- a/frameworks/projects/Style/src/main/resources/style-manifest.xml
+++ b/frameworks/projects/Style/src/main/resources/style-manifest.xml
@@ -60,6 +60,7 @@
   <component id="FlexLayout" class="org.apache.royale.style.beads.FlexLayout"/>
   <component id="Link" class="org.apache.royale.style.Link"/>
   <component id="HoverState" 
class="org.apache.royale.style.stylebeads.states.HoverState"/>
+  <component id="Toast" class="org.apache.royale.style.Toast"/>
   <component id="Group" class="org.apache.royale.style.Group"/>
   <component id="DataContainer" class="org.apache.royale.style.DataContainer"/>
   <component id="List" class="org.apache.royale.style.List"/>
@@ -73,6 +74,7 @@
   <component id="ListView" class="org.apache.royale.style.beads.ListView"/>
   
   <component id="DataState" 
class="org.apache.royale.style.stylebeads.states.attribute.DataState"/>
+  <component id="NotDataState" 
class="org.apache.royale.style.stylebeads.states.attribute.NotDataState"/>
   <component id="AriaState" 
class="org.apache.royale.style.stylebeads.states.attribute.AriaState"/>
   <component id="InertState" 
class="org.apache.royale.style.stylebeads.states.attribute.InertState"/>
   <component id="FocusWithinState" 
class="org.apache.royale.style.stylebeads.states.FocusWithinState"/>
@@ -88,6 +90,7 @@
   <component id="MarkerState" 
class="org.apache.royale.style.stylebeads.states.pseudo.MarkerState"/>
   <component id="PlaceholderState" 
class="org.apache.royale.style.stylebeads.states.pseudo.PlaceholderState"/>
   <component id="SelectionState" 
class="org.apache.royale.style.stylebeads.states.pseudo.SelectionState"/>
+  <component id="NotState" 
class="org.apache.royale.style.stylebeads.states.NotState"/>
   <component id="PeerPseudo" 
class="org.apache.royale.style.stylebeads.states.PeerPseudo"/>
 
   <component id="BackgroundStyle" 
class="org.apache.royale.style.stylebeads.BackgroundStyle"/>
@@ -143,6 +146,11 @@
   <component id="WordBreak" 
class="org.apache.royale.style.stylebeads.typography.WordBreak"/>
 
   <component id="Animation" 
class="org.apache.royale.style.stylebeads.anim.Animation"/>
+  <component id="CustomAnimation" 
class="org.apache.royale.style.stylebeads.anim.CustomAnimation"/>
+  <component id="Keyframes" 
class="org.apache.royale.style.stylebeads.anim.Keyframes"/>
+  <component id="AnimationDuration" 
class="org.apache.royale.style.stylebeads.anim.AnimationDuration"/>
+  <component id="AnimationTimingFunction" 
class="org.apache.royale.style.stylebeads.anim.AnimationTimingFunction"/>
+  <component id="Transition" 
class="org.apache.royale.style.stylebeads.anim.Transition"/>
   <component id="TransitionBehavior" 
class="org.apache.royale.style.stylebeads.anim.TransitionBehavior"/>
   <component id="TransitionDelay" 
class="org.apache.royale.style.stylebeads.anim.TransitionDelay"/>
   <component id="TransitionDuration" 
class="org.apache.royale.style.stylebeads.anim.TransitionDuration"/>
@@ -322,5 +330,6 @@
   <component id="StepsSkin" class="org.apache.royale.style.skins.StepsSkin"/>
   <component id="StepSkin" class="org.apache.royale.style.skins.StepSkin"/>
   <component id="IStepSkin" class="org.apache.royale.style.skins.IStepSkin"/>
+  <component id="ToastSkin" class="org.apache.royale.style.skins.ToastSkin"/>
 
 </componentPackage>
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Application.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Application.as
index 7fbb61f955..145cec936f 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Application.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Application.as
@@ -27,11 +27,19 @@ package org.apache.royale.style
 
        public class Application extends org.apache.royale.core.Application
        {
+               private static var _current:org.apache.royale.style.Application;
+               /**
+                * Global getter to get a reference to the top-level application
+                */
+               public static function get 
current():org.apache.royale.style.Application{
+                       return _current;
+               }
                public function Application()
                {
                        super();
                        valuesImpl = new AllCSSValuesImpl();
                addBead(new ApplicationDataBinding());
+                       _current = this;
                        ThemeManager.instance.registerTheme(new StyleTheme());
                }
 
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/StyleUIBase.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/StyleUIBase.as
index f0795c507c..56eaf4859f 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/StyleUIBase.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/StyleUIBase.as
@@ -115,7 +115,7 @@ package org.apache.royale.style
                 * 
                 * Most components have four possible sizes, but specific 
components may choose to support a different set of sizes as needed.
                 */
-               [Inspectable(category="General", enumeration="sm,md,lg,xl", 
defaultValue="md")]
+               [Inspectable(category="General", enumeration="xs,sm,md,lg,xl", 
defaultValue="md")]
                public function get size():String
                {
                        return _size;
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Toast.as 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Toast.as
new file mode 100644
index 0000000000..853010e84b
--- /dev/null
+++ b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Toast.as
@@ -0,0 +1,304 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.style
+{
+  import org.apache.royale.core.IHasLabel;
+  import org.apache.royale.core.IPopUpHost;
+  import org.apache.royale.debugging.assert;
+  import org.apache.royale.style.elements.Div;
+  import org.apache.royale.style.skins.IToastSkin;
+  import org.apache.royale.utils.Timer;
+  import org.apache.royale.events.Event;
+  
+  COMPILE::SWF{
+    //compilation support only:
+    import flash.utils.setTimeout;
+  }
+  
+  COMPILE::JS
+  {
+    import org.apache.royale.core.WrappedHTMLElement;
+  }
+  
+  [Event(name="accept", type="org.apache.royale.events.Event")]
+  [Event(name="close", type="org.apache.royale.events.Event")]
+  public class Toast extends StyleUIBase implements IHasLabel
+  {
+
+    
+    public function Toast(content:String = null, autoClose:uint=0)
+    {
+      super();
+      if(content){
+        label = content;
+      }
+      this.autoClose = autoClose;
+    }
+
+
+    public static const INFO:String = "info";
+    public static const NEGATIVE:String = "negative";
+    public static const POSITIVE:String = "positive";
+    public static const WARNING:String = "warning";
+    public static const SUCCESS:String = "success";
+    
+    
+    override public function addedToParent():void{
+      //This should not be added to anything other than an IPopUpHost. 
+      //In particular, fx:Declarations nodes in Royale don't work as they 
should for Visual components. They should not add to display, but they do.
+      super.addedToParent();
+      if (!(parent is IPopUpHost)) {
+        parent.removeElement(this)
+      }
+    }
+    
+    private var _label:String = "";
+    public function get label():String
+    {
+      return _label;
+    }
+    
+    public function set label(value:String):void
+    {
+      COMPILE::JS
+      {
+        if(_label != value){
+          _label = value;
+          _contentNode.text = value;
+        }
+      }
+    }
+    
+    private var actionButton:IStyleUIBase;
+    private var _action:String;
+    public function get action():String
+    {
+       return _action;
+    }
+    
+    public function set action(value:String):void
+    {
+      if (value != _action) {
+        _action = value;
+        updateActionButton();
+      }
+    }
+    
+    private function updateActionButton():void{
+      if (actionButton) {
+        actionButton.removeEventListener("click",onAction);
+        body.removeElement(actionButton)
+      }
+      var toastSkin:IToastSkin = skin as IToastSkin;
+      if (_action && toastSkin) {
+        actionButton = toastSkin.getActionButton(_action);
+        actionButton.addEventListener("click",onAction);
+        body.addElement(actionButton)
+      }
+    }
+    
+    private function onAction(ev:Event):void{
+      if(_shown){
+        dispatchEvent(new Event("accept"));
+      }
+      hide();
+    }
+
+    private var _flavorIcon:IStyleUIBase;
+    private var _flavor:String;
+    public function get flavor():String
+    {
+       return _flavor;
+    }
+    
//"base","primary","secondary","accent","info","success","warning","error","neutral"
+    [Inspectable(category="General", 
enumeration="info,success,positive,negative,warning")]
+    /**
+     * Set the flavor of the Toast
+     * One of info, success, positive and negative. warning also appears to be 
an option
+     * To set the Toast to the default, specify an empty string
+     */
+    public function set flavor(value:String):void
+    {
+      if(value != _flavor){
+        switch(value){
+          case "info":
+          case "positive":
+          case "success":
+          case "negative":
+          case "error":
+          case "warning":
+          case "":
+            break;
+          default:
+            throw new Error("Unknown flavor: " + value);
+        }
+        _flavor = value;
+        
+        if (skin) {
+          updateFlavorIcon();
+        }
+      }
+    }
+    
+    private function updateFlavorIcon():void{
+      if (_flavorIcon) {
+        _body.removeElement(_flavorIcon);
+      }
+      var toastSkin:IToastSkin = skin as IToastSkin;
+      _flavorIcon = toastSkin.getIcon(_flavor);
+      if (_flavorIcon) {
+        _body.addElementAt(_flavorIcon,0);
+      }
+    }
+
+    private var timer:Timer;
+    public function show():void{
+      if(_shown){
+        return;
+      }
+      _shown = true;
+      toggleAttribute("data-hiding", false);
+      toggleAttribute("data-showing", true);
+      Application.current.popUpParent.addElement(this);
+    }
+    
+    /**
+     * @private
+     * for use from skins when inbound animations are done
+     */
+    public function afterShow():void{
+      if(autoClose){
+        timer = new Timer(autoClose);
+        timer.addEventListener(Timer.TIMER,onTimer)
+        timer.start();
+      }
+    }
+
+    private function onTimer(ev:Event):void{
+      timer.removeEventListener(Timer.TIMER,onTimer);
+      hide();
+    }
+    
+    private var _shown:Boolean;
+    public function hide():void{
+      if(!_shown){
+        return;
+      }
+      _shown = false;
+      toggleAttribute("data-showing", false);
+      toggleAttribute("data-hiding", true);
+      dispatchEvent(new Event("close"));
+    }
+    
+    /**
+     * @private
+     * for use from skins when outbound animations are done
+     */
+    public function afterHide():void{
+      if (this.parent)
+        Application.current.popUpParent.removeElement(this);
+      toggleAttribute("data-showing", false);
+      toggleAttribute("data-hiding", false);
+    }
+    
+    private var _autoClose:uint = 0;
+
+    /**
+     * Number of milliseconds the Toast will remain open.
+     * A value of 0 (default) will cause it to remain open until closed.
+     */
+    public function get autoClose():uint
+    {
+       return _autoClose;
+    }
+
+    public function set autoClose(value:uint):void
+    {
+       _autoClose = value;
+    }
+    
+    private var _toast:Div;
+    /**
+     * The container node for all the visual content of the Toast message and 
its controls
+     */
+    public function get toast():Div{
+      return _toast;
+    }
+    private var _body:Div;
+    /**
+     * The container node for the message with optional action UI control
+     */
+    public function get body():Div{
+      return _body;
+    }
+    
+    private var _contentNode:Div;
+    /**
+     * The message content container - for label property to populate with 
text content
+     */
+    public function get contentNode():Div{
+      return _contentNode;
+    }
+    
+    private var _buttons:Div;
+    /**
+     * The button container for the toast controls (explicit close button)
+     */
+    public function get buttons():Div{
+      return _buttons;
+    }
+    
+    COMPILE::JS
+    override protected function createElement():WrappedHTMLElement{
+      var elem:WrappedHTMLElement = super.createElement();
+      _toast = new Div();
+      _body = new Div();
+      _contentNode = new Div();
+      _body.addElement(_contentNode);
+      _toast.addElement(_body)
+      _buttons = new Div();
+      _toast.addElement(_buttons);
+      elem.appendChild(toast.element);
+      return elem;
+    }
+    
+    override protected function applySkin():void{
+      var toastSkin:IToastSkin = skin as IToastSkin;
+      assert(toastSkin is IToastSkin, "Toast requires a skin that implements 
IToastSkin");
+      var styles:Array = toastSkin.toastContentStyles || [];
+      _toast.setStyles(styles, true);
+      styles = toastSkin.textLayoutStyles || [];
+      _contentNode.setStyles(styles,true);
+      styles = toastSkin.toastBodyStyles || [];
+      _body.setStyles(styles,true);
+      updateFlavorIcon();
+      if (_action && !actionButton) {
+        updateActionButton()
+      }
+      styles = toastSkin.buttonsLayoutStyles || [];
+      _buttons.setStyles(styles,true);
+      if (!_buttons.numElements) {
+        var button:IStyleUIBase = toastSkin.getCloseButton()
+        button.addEventListener("click",hide);
+        _buttons.addElement(button);
+      }
+    }
+
+  }
+}
\ No newline at end of file
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 0698f3af04..cc0a8d08c8 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
@@ -51,374 +51,5 @@ package org.apache.royale.style.colors
                        return "";
                }
 
-               /**
-                * 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, darkMode:Boolean = false):Array
-               {
-                       var r:Number = (color >> 16) & 0xFF;
-                       var g:Number = (color >> 8) & 0xFF;
-                       var b:Number = color & 0xFF;
-
-                       //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;
-
-                       if (t <= 50)
-                       {
-                               var toBase:Number = t / 50;
-                               outR = 255 + (r - 255) * toBase;
-                               outG = 255 + (g - 255) * toBase;
-                               outB = 255 + (b - 255) * toBase;
-                       }
-                       else
-                       {
-                               var toBlack:Number = (t - 50) / 50;
-                               outR = r * (1 - toBlack);
-                               outG = g * (1 - toBlack);
-                               outB = b * (1 - toBlack);
-                       }
-
-                       return [Math.round(outR), Math.round(outG), 
Math.round(outB)];*/
-               }
-
-               /**
-                * Convenience helper for callers that have separate channel 
values.
-                */
-               public static function getVariationRGB(r:Number, g:Number, 
b:Number, grayValue:Number):Array
-               {
-                       var rr:uint = uint(pinValue(r, 0, 255));
-                       var gg:uint = uint(pinValue(g, 0, 255));
-                       var bb:uint = uint(pinValue(b, 0, 255));
-                       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 75581ad554..111a876f28 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
@@ -83,6 +83,51 @@ package org.apache.royale.style.colors
                        "zinc": 0x71717B
                };
                
+               private static const lchLookups:Object = {init:false};
+               private static function getLCHLookups():Object{
+                       if (lchLookups.init === false) {
+                               delete lchLookups.init;
+                               for (var key:String in BASE_COLORS) {
+                                       var col:uint = BASE_COLORS[key];
+                                       lchLookups[key] = 
ColorUtils.rgb_ToOKLCH([(col>>16)&0xff,(col>>8)&0xff,col&0xff])
+                               }
+                               //add white and black
+                               
+                               
+                       }
+                       return lchLookups;
+               }
+               
+               public static function estimateFromRGB(rgb:Array, 
customOklchLookups:Object = null):ColorSwatch{
+                       var BASE_COLORS_OKLCH:Object = customOklchLookups || 
getLCHLookups();
+                       var bestName:String = null;
+                       var inputAsOKLCH:Array =  ColorUtils.rgb_ToOKLCH(rgb);
+                       var bestDist:Number = Number.MAX_VALUE;
+                       for (var name:String in BASE_COLORS_OKLCH) {
+                               var ref:Array = BASE_COLORS_OKLCH[name];
+                               var d:Number = 
ColorUtils.oklchDistance(inputAsOKLCH, ref);
+                               if (d < bestDist) {
+                                       bestDist = d;
+                                       bestName = name;
+                               }
+                       }
+                       var base:Array = BASE_COLORS_OKLCH[bestName];
+                       var ramp:Object = ColorUtils.getOklchRamp(base);
+                       var bestShade:uint = 500;
+                       bestDist = Number.MAX_VALUE;
+                       for (var shadeKey:String in ramp) {
+                               ref = ramp[shadeKey];
+                               d = ColorUtils.oklchDistance(inputAsOKLCH, ref);
+                               if (d < bestDist)
+                               {
+                                       bestDist = d;
+                                       bestShade = uint(shadeKey);
+                               }
+                       }
+                       return new ColorSwatch(bestName,bestShade);
+               }
+               
+               
                private static const exceptions:Array = [
                        "transparent",
                        "currentColor",
@@ -103,7 +148,7 @@ package org.apache.royale.style.colors
                        var baseColor:uint = CSSUtils.toColor(base);
                        // Convert from 50,100,200... to 5,10,20... for easier 
math.
                //      shade = Math.round(shade/10);
-                       rgb = 
CSSColor.getVariation(baseColor,Math.round(shade/10),darkMode);
+                       rgb = 
ColorUtils.getVariation(baseColor,Math.round(shade/10),darkMode);
                        assert(opacity >= 0 && opacity <= 100, "Opacity must be 
between 0 and 100");
                        colorBase = swatch;
                        colorShade = shade;
@@ -127,14 +172,17 @@ package org.apache.royale.style.colors
                public var dark:Boolean;
                
                /**
-                * create a ColorSwatch variant from this instance
-                * @param alternateShade - alternate shade. If you want to keep 
the same shade and adjust opacity, set this to NaN
-                * @param alternateOpacity - if not set it will inherit the 
original value from this instance
-                * @return a new ColorSwatch with different shade or opacity 
(or both)
-                */
-               public function getVariant(alternateShade:Number, 
alternateOpacity:Number = NaN):ColorSwatch{
+         * create a ColorSwatch variant from this instance
+         * @param alternateShade - alternate shade. If you want to keep the 
same shade and adjust opacity, set this to NaN
+         * @param alternateOpacity - if not set it will inherit the original 
value from this instance
+         * @param applyDelta if true, the alternate values will be applied as 
deltas to existing values to create the variant
+         * @return a new ColorSwatch with different shade or opacity (or both)
+         */
+               public function getVariant(alternateShade:Number, 
alternateOpacity:Number = NaN, applyDelta:Boolean = false):ColorSwatch{
                        if (isNaN(alternateShade)) alternateShade = colorShade;
+                       else if (applyDelta) alternateShade = colorShade + 
alternateShade;
                        if (isNaN(alternateOpacity)) alternateOpacity = 
colorOpacity;
+                       else if (applyDelta) alternateOpacity = colorOpacity + 
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;
@@ -160,7 +208,7 @@ package org.apache.royale.style.colors
                        return name in BASE_COLORS;
                }
                
-               public static function getColorValue(name:String):Boolean{
+               public static function getColorValue(name:String):uint{
                        return BASE_COLORS[name];
                }
                
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/ColorUtils.as
similarity index 62%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/CSSColor.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/colors/ColorUtils.as
index 0698f3af04..057393c547 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/ColorUtils.as
@@ -19,41 +19,26 @@
 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
+       public class ColorUtils
        {
-               private function CSSColor()
+               private function ColorUtils()
                {
                        
                }
-               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(" ");
-
-                       switch (space)
-                       {
-                               case "rgb":
-                               case "hsl":
-                               case "hwb":
-                               case "lab":
-                               case "lch":
-                               case "oklab":
-                               case "oklch":
-                                       return withAlpha ? space + "(" + 
channels + " / " + alphaString + ")" : space + "(" + channels + ")";
-                               default:
-                                       assert(false, "Unsupported color space: 
" + space);
-                                       break;
-                       }
-                       return "";
-               }
-
+               
                /**
-                * Returns an RGB array on a white -> base -> black ramp.
-                * 0 is white, 50 is the input color, 100 is black.
+                * Returns an RGB array representing a perceptually-balanced 
variation of the input color.
+                * Uses OKLCH color space to maintain consistent hue and 
saturation across different lightness levels.
+                *
+                * @param color The base color as a uint (0xRRGGBB).
+                * @param grayValue A value from 0 to 100.
+                *        Values < 50 transition toward a high-lightness 
aesthetic target (~97% lightness).
+                *        Value of 50 returns the input color (base).
+                *        Values > 50 transition toward a low-lightness 
aesthetic target (~12% lightness).
+                * @param darkMode If true, inverts the shading scale to 
optimize the color for dark theme contexts.
+                * @return An Array of [R, G, B] values (0-255).
                 */
                public static function getVariation(color:uint, 
grayValue:Number, darkMode:Boolean = false):Array
                {
@@ -95,7 +80,7 @@ package org.apache.royale.style.colors
                /**
                 * Convenience helper for callers that have separate channel 
values.
                 */
-               public static function getVariationRGB(r:Number, g:Number, 
b:Number, grayValue:Number):Array
+               public static function getVariationRGB(r:Number, g:Number, 
b:Number, grayValue:Number, darkMode:Boolean = false):Array
                {
                        var rr:uint = uint(pinValue(r, 0, 255));
                        var gg:uint = uint(pinValue(g, 0, 255));
@@ -272,6 +257,59 @@ package org.apache.royale.style.colors
                        900: 0.45
                }
                
+               public static function getOklchRamp(base:Array):Object{
+                       var ramp:Object = {};
+                       for (var shade:String in shading_factors)
+                       {
+                               var m:Number = shading_factors[shade];
+                               
+                               // Lightness scaling
+                               var L:Number = base[0] * m;
+                               
+                               // Chroma scaling (slightly reduced for darker 
shades)
+                               var C:Number = base[1] * (m < 1 ? m : 1);
+                               
+                               // Hue stays constant
+                               var H:Number = base[2];
+                               
+                               ramp[shade] = [L,C,H];
+                       }
+                       return ramp;
+               }
+               
+               public static function oklchDistance(a:Array, b:Array):Number
+               {
+                       // Hue difference with wrap-around
+                       var dh:Number = Math.abs(a[2] - b[2]);
+                       if (dh > 180) dh = 360 - dh;
+                       
+                       var dL:Number = a[0] - b[0];
+                       var dC:Number = a[1] - b[1];
+                       
+                       return Math.sqrt(dL*dL + dC*dC + dh*dh);
+               }
+               
+               public static function flattenRGBAOverBackground(fg_rgb:Array, 
alpha:Number, bg_rgb:Array = null):Array
+               {
+                       assert(alpha>=0 && alpha<=1,'alpha out of range');
+                       // Foreground
+                       var rF:uint = fg_rgb[0] & 0xff;
+                       var gF:uint = fg_rgb[1] & 0xff;
+                       var bF:uint = fg_rgb[2] & 0xff;
+                       
+                       // Background
+                       var rB:uint = bg_rgb ? bg_rgb[0] & 0xff : 0xFF;
+                       var gB:uint = bg_rgb ? bg_rgb[1] & 0xff : 0xFF;
+                       var bB:uint = bg_rgb ? bg_rgb[2] & 0xff : 0xFF;
+                       
+                       // Composite
+                       var r:uint = rF * alpha + rB * (1 - alpha);
+                       var g:uint = gF * alpha + gB * (1 - alpha);
+                       var b:uint = bF * alpha + bB * (1 - alpha);
+                       
+                       return [r,g,b]
+               }
+               
                private static var inverted_factors:Object;
                                
                private static const SHADE_KEYS:Array = [];
@@ -289,7 +327,7 @@ package org.apache.royale.style.colors
                                trace('inverted', inverted_factors);
                        }
                        const factors:Object = darkMode ? inverted_factors : 
shading_factors;
-                       const shadeKeys:Array = darkMode ? 
CSSColor.INVERTED_SHADE_KEYS : CSSColor.SHADE_KEYS;
+                       const shadeKeys:Array = darkMode ? 
ColorUtils.INVERTED_SHADE_KEYS : ColorUtils.SHADE_KEYS;
                        if (!shadeKeys.length) {
                                //populate it first time
                                COMPILE::JS{
@@ -400,8 +438,8 @@ package org.apache.royale.style.colors
                                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 oklch:Array = rgb_ToOKLCH([r1,g1,b1]);
+                               var rgb2:Array = oklch_ToRGB(oklch);
                                
                                var r2:uint = rgb2[0];
                                var g2:uint = rgb2[1];
@@ -420,5 +458,154 @@ package org.apache.royale.style.colors
                                );
                        }
                }*/
+               
+               /**
+                * Compute WCAG relative luminance from sRGB (0–255)
+                */
+               private static function relativeLuminance(rgb:Array):Number {
+                       function chan(v:Number):Number {
+                               v /= 255.0;
+                               return (v <= 0.04045) ? (v / 12.92) : 
Math.pow((v + 0.055) / 1.055, 2.4);
+                       }
+                       var r:Number = chan(rgb[0]);
+                       var g:Number = chan(rgb[1]);
+                       var b:Number = chan(rgb[2]);
+                       return 0.2126 * r + 0.7152 * g + 0.0722 * b;
+               }
+               
+               /**
+                * WCAG contrast ratio between two RGB colors
+                */
+               public static function contrast(a:Array, b:Array):Number {
+                       var L1:Number = relativeLuminance(a);
+                       var L2:Number = relativeLuminance(b);
+                       var lighter:Number = Math.max(L1, L2);
+                       var darker:Number  = Math.min(L1, L2);
+                       return (lighter + 0.05) / (darker + 0.05);
+               }
+               
+               /**
+                * Generate a WCAG‑compliant contrast color in OKLCH by:
+                * 1. Binary‑searching lightness (L) to find the minimum value 
that meets contrast.
+                * 2. Binary‑searching chroma (C) to find the maximum valid 
chroma at that L.
+                *
+                * The resulting color preserves the hue of the input color and 
retains as much
+                * chroma as possible, producing a contrast color that remains 
visually related
+                * to the original color rather than collapsing to grayscale.
+                */
+               public static function generateContrastLCH(bgLch:Array, 
wantLight:Boolean):Array {
+                       var L:Number = bgLch[0];
+                       var C:Number = bgLch[1];
+                       var h:Number = bgLch[2];
+                       
+                       var bgRgb:Array = oklch_ToRGB(bgLch);
+                       
+                       // -----------------------------
+                       // 1. BINARY SEARCH FOR LIGHTNESS
+                       // -----------------------------
+                       var low:Number;
+                       var high:Number;
+                       
+                       if (wantLight) {
+                               low = L;
+                               high = 1.0;
+                       } else {
+                               low = 0.0;
+                               high = L;
+                       }
+                       
+                       var mid:Number;
+                       var safeC:Number;
+                       var test:Array;
+                       var rgb:Array;
+                       
+                       // 20 iterations = sub‑pixel precision
+                       for (var i:int = 0; i < 20; i++) {
+                               mid = (low + high) * 0.5;
+                               
+                               // Stability chroma curve (prevents invalid 
OKLCH at extremes)
+                               safeC = C * (1 - Math.abs(mid - 0.5) * 2);
+                               safeC = pinValue(safeC, 0, C);
+                               
+                               test = [mid, safeC, h];
+                               rgb = oklch_ToRGB(test);
+                               
+                               var cr:Number = contrast(rgb, bgRgb);
+                               
+                               if (cr >= 4.5) {
+                                       if (wantLight) high = mid;
+                                       else low = mid;
+                               } else {
+                                       if (wantLight) low = mid;
+                                       else high = mid;
+                               }
+                       }
+                       
+                       var L_final:Number = mid;
+                       
+                       // -----------------------------
+                       // 2. BINARY SEARCH FOR CHROMA
+                       // -----------------------------
+                       var cLow:Number = 0.0;
+                       var cHigh:Number = C;
+                       var cMid:Number;
+                       var bestC:Number = 0.0;
+                       
+                       for (i = 0; i < 20; i++) {
+                               cMid = (cLow + cHigh) * 0.5;
+                               
+                               // Candidate with this chroma
+                               test = [L_final, cMid, h];
+                               rgb = oklch_ToRGB(test);
+                               
+                               // Check if round‑trip OKLCH is valid
+                               var rt:Array = rgb_ToOKLCH(rgb);
+                               var valid:Boolean = Math.abs(rt[0] - L_final) < 
0.02; // lightness must survive round‑trip
+                               
+                               // Check contrast
+                               var cr2:Number = contrast(rgb, bgRgb);
+                               
+                               if (valid && cr2 >= 4.5) {
+                                       bestC = cMid;   // keep this chroma
+                                       cLow = cMid;    // try for more
+                               } else {
+                                       cHigh = cMid;   // too much chroma → 
reduce
+                               }
+                       }
+                       
+                       // Final brand‑safe contrast color
+                       return [L_final, bestC, h];
+               }
+               
+               /**
+                * Given an RGB background, return a strong‑contrast RGB 
foreground.
+                */
+               public static function chooseContrastRGB(bgRgb:Array):Array {
+                       
+                       // Predefined white/black
+                       const WHITE:Array = [255, 255, 255];
+                       const BLACK:Array = [0, 0, 0];
+                       
+                       var cWhite:Number = contrast(bgRgb, WHITE);
+                       var cBlack:Number = contrast(bgRgb, BLACK);
+                       
+                       // Fast path: if either passes WCAG AA, choose the 
stronger
+                       var whitePass:Boolean = (cWhite >= 4.5);
+                       var blackPass:Boolean = (cBlack >= 4.5);
+                       
+                       if (whitePass || blackPass) {
+                               return (cWhite > cBlack) ? WHITE : BLACK;
+                       }
+                       
+                       // Slow path: generate a corrected OKLCH foreground
+                       var bgLch:Array = rgb_ToOKLCH(bgRgb);
+                       var L:Number = bgLch[0];
+                       
+                       // If background is light, generate dark text; if dark, 
generate light text
+                       var wantLight:Boolean = (L < 0.6);
+                       
+                       var correctedLch:Array = generateContrastLCH(bgLch, 
wantLight);
+                       return oklch_ToRGB(correctedLch);
+               }
        }
 }
\ No newline at end of file
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 76480f9496..1a7740e8d3 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
@@ -20,7 +20,6 @@ package org.apache.royale.style.colors
 {
        import org.apache.royale.style.util.CSSLookup;
        import org.apache.royale.utils.CSSUtils;
-       
        import org.apache.royale.debugging.assert;
 
        public class ThemeColorSet
@@ -56,6 +55,22 @@ package org.apache.royale.style.colors
 
                COMPILE::JS
                private const storage:Map = new Map();
+               
+               private const lchLookups:Object = {init:false};
+               private function getLCHLookups():Object{
+                       if (lchLookups.init === false) {
+                               delete lchLookups.init;
+                               var key:String;
+                               for each(key in _fieldNames) {
+                                       var baseColor:String = 
getThemeBaseColor(key);
+                                       if (baseColor) {
+                                               var col:uint 
=ColorSwatch.getColorValue(baseColor);
+                                               lchLookups[baseColor] = 
ColorUtils.rgb_ToOKLCH([(col>>16)&0xff,(col>>8)&0xff,col&0xff])
+                                       }
+                               }
+                       }
+                       return lchLookups;
+               }
 
                /**
                 * Subclasses must specify colorBase before calling this 
constructor.
@@ -146,54 +161,65 @@ package org.apache.royale.style.colors
                }
                
                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);
+                       var result:ColorSwatch = 
findContrastVariant(original.colorBase,original.colorShade,original.dark,false, 
true);
+                       if (original.colorOpacity != 100) {
+                               result = 
result.getVariant(NaN,original.colorOpacity);
                        }
-                       return new ColorSwatch(nameVariant,500,opacity,dark);
+                       return result
                }
                
                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);
+                       var result:ColorSwatch = 
findContrastVariant(original.colorBase,original.colorShade,original.dark,true, 
true);
+                       if (original.colorOpacity != 100) {
+                               result = 
result.getVariant(NaN,original.colorOpacity);
                        }
-                       return new ColorSwatch(nameVariant,500,opacity,dark);
+                       return result;
                }
                
-               private static function 
registerContrastVariant(nameVariant:String, swatch:String, 
shade:Number,dark:Boolean, weak:Boolean):void{
+               private var contrastLookupSpecifiers:Object = {};
+               
+               /**
+         * Finds a contrast variant ColorSwatch based on the pararmeters 
passed in
+         * @param swatch the name of a color swatch (can be outside this set)
+         * @param shade the shade 50 - 900
+         * @param dark tbd
+         * @param weak if true then a weak contrast is returned, otherwise a 
strong contrast
+         * @param limitRange if true then limit lookups to this color set only
+         * @return
+         */
+               public function findContrastVariant(swatch:String, 
shade:Number,dark:Boolean, weak:Boolean, limitRange:Boolean=false):ColorSwatch{
+                       const lookupKey:String = 
swatch+'$$'+shade+'$$'+dark+'$$'+weak+'$$';
+
+                       var existing:String = 
contrastLookupSpecifiers[lookupKey];
+                       if (existing) {
+                               
+                               return ColorSwatch.fromSpecifier(existing);
+                       }
                        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;
+                       var colorVals:Array = 
ColorUtils.getVariation(baseColor,shade,dark);
+                       var bgLch:Array = ColorUtils.rgb_ToOKLCH(colorVals);
+                       var L:Number = bgLch[0];
+
+               //      var wantLight:Boolean = 
(ColorUtils.contrast([255,255,255], colorVals) < ColorUtils.contrast([0,0,0], 
colorVals));
+                       var wantLight:Boolean = (L < .62);
                        
+                       // Strong or weak contrast?
+                       var targetLch:Array = 
ColorUtils.generateContrastLCH(bgLch, wantLight);
                        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
+                               // Weak contrast = reduce chroma + move L 
slightly toward bg
+                               targetLch[1] *= 0.4;     // reduce chroma
+                               targetLch[0] = (targetLch[0] + L) * 0.5; // 
blend toward background
                        }
                        
-                       colorVals = CSSColor.oklch_ToRGB(fg);
-                       
CSSLookup.register(nameVariant,'rgb('+colorVals.join(',')+')');
+                       var fg:Array = targetLch;
+                       colorVals = ColorUtils.oklch_ToRGB(fg);
+                       var lookups:Object = limitRange ? getLCHLookups() : 
null;
+                       var ret:ColorSwatch = 
ColorSwatch.estimateFromRGB(colorVals,lookups);
+                       contrastLookupSpecifiers[lookupKey] = ret.toString()
+
+                       return ret;
                }
                
                public function fromJSON(obj:Object):void{
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/elements/Textarea.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/elements/Textarea.as
index 339e8c7e1e..88c63240f2 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/elements/Textarea.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/elements/Textarea.as
@@ -215,6 +215,88 @@ package org.apache.royale.style.elements
                                textarea.value = value;
                        }
                }
+               
+               public function get readonly():Boolean
+               {
+                       COMPILE::JS
+                       {
+                               return textarea.readOnly;
+                       }
+                       COMPILE::SWF
+                       {
+                               return false
+                       }
+               }
+               
+               public function set readonly(value:Boolean):void
+               {
+                       COMPILE::JS
+                       {
+                               textarea.readOnly = value;
+                       }
+               }
+               
+               public function get placeholder():String
+               {
+                       COMPILE::JS
+                       {
+                               return textarea.placeholder;
+                       }
+                       COMPILE::SWF
+                       {
+                               return null
+                       }
+               }
+               
+               public function set placeholder(value:String):void
+               {
+                       COMPILE::JS
+                       {
+                               //set the content in the textArea
+                               textarea.placeholder = value;
+                       }
+               }
+               
+               private var _required:Boolean;
+               
+               public function get required():Boolean
+               {
+                       return _required;
+               }
+               
+               public function set required(value:Boolean):void
+               {
+                       if(value != !!_required){
+                               toggleAttribute('required',value);
+                       }
+                       _required = value;
+               }
+               
+               private var _invalid:Boolean;
+               /**
+                * Indicates whether the current state of the component is 
invalid.
+                * This can be used to apply error styles to the component.
+                *
+                * The Checkbox skin should specify invalid styles if desired.
+                *
+                * @languageversion 3.0
+                * @productversion Royale 1.0.0
+                */
+               public function get invalid():Boolean
+               {
+                       return _invalid;
+               }
+               
+               public function set invalid(value:Boolean):void
+               {
+                       COMPILE::JS
+                       {
+                               if(value != !!_invalid){
+                                       toggleAttribute("data-invalid", value);
+                               }
+                       }
+                       _invalid = value;
+               }
 
                override protected function getTag():String
                {
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 a918878211..514c1be7dd 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
@@ -281,8 +281,9 @@ package org.apache.royale.style.skins
                                var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
                                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);
+               //              var disabledFillColor:ColorSwatch  = 
colorSet.getSwatch(ThemeColorSet.BASE, 200, 50);
+               //              var disabledColor:ColorSwatch = 
colorSet.getWeakContrastSwatch(disabledFillColor);
+                               var disabledColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 300,50);
                                
                                _checkIcon = new Div();
                                var size:Number = 16 * getMultiplier();
@@ -348,8 +349,10 @@ package org.apache.royale.style.skins
                        if(!_indeterminateIcon){
                                var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
                                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);
+                       //      var disabledFillColor:ColorSwatch  = 
colorSet.getSwatch(ThemeColorSet.BASE, 200, 50);
+                       //      var disabledColor:ColorSwatch = 
colorSet.getWeakContrastSwatch(disabledFillColor);
+                               
+                               var disabledColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 300,50);
                                
                                _indeterminateIcon = new Div();
                                var size:Number = 16 * getMultiplier();
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/IToastSkin.as
similarity index 61%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/IToastSkin.as
index 2c5260018b..a640d3d67d 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/IToastSkin.as
@@ -16,16 +16,24 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.layout
+package org.apache.royale.style.skins
 {
-       import org.apache.royale.style.stylebeads.LeafStyleBase;
-       import org.apache.royale.debugging.assert;
-
-       public class InsetBlock extends InsetBase
+       import org.apache.royale.style.IStyleSkin;
+       import org.apache.royale.style.IStyleUIBase;
+       import org.apache.royale.style.StyleUIBase;
+       
+       public interface IToastSkin extends IStyleSkin
        {
-               public function InsetBlock()
-               {
-                       super("inset-y", "inset-block");
-               }
+               //function updateStyles():void;
+               //function get labelStyles():Array;
+               
+               function get toastContentStyles():Array;
+               function get textLayoutStyles():Array;
+               function get buttonsLayoutStyles():Array;
+               function get toastBodyStyles():Array;
+               
+               function getIcon(flavor:String):IStyleUIBase;
+               function getActionButton(action:String):IStyleUIBase;
+               function getCloseButton():IStyleUIBase;
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ToastSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ToastSkin.as
new file mode 100644
index 0000000000..3bcf209a66
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ToastSkin.as
@@ -0,0 +1,381 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.style.skins
+{
+       import org.apache.royale.style.StyleSkin;
+       import org.apache.royale.style.Icon;
+       import org.apache.royale.style.IStyleUIBase;
+       import org.apache.royale.core.IStrand;
+       import org.apache.royale.style.Toast;
+       import org.apache.royale.style.colors.ColorSwatch;
+       import org.apache.royale.style.colors.ThemeColorSet;
+       import org.apache.royale.style.elements.Button;
+       import org.apache.royale.style.stylebeads.StyleBeadBase;
+       import org.apache.royale.style.stylebeads.anim.Animation;
+       import org.apache.royale.style.stylebeads.anim.CustomAnimation;
+       import org.apache.royale.style.util.AnimationManager;
+       import org.apache.royale.style.stylebeads.anim.Transition;
+       import org.apache.royale.style.stylebeads.flexgrid.Flex;
+       import org.apache.royale.style.stylebeads.flexgrid.JustifyContent;
+       import org.apache.royale.style.stylebeads.layout.Bottom;
+       import org.apache.royale.style.stylebeads.layout.Display;
+       import org.apache.royale.style.stylebeads.flexgrid.AlignItems;
+       import org.apache.royale.style.stylebeads.interact.UserSelect;
+       import org.apache.royale.style.stylebeads.layout.Position;
+       import org.apache.royale.style.stylebeads.layout.ZIndex;
+       import org.apache.royale.style.stylebeads.sizing.HeightStyle;
+       import org.apache.royale.style.stylebeads.sizing.WidthStyle;
+       import org.apache.royale.style.stylebeads.border.BorderRadius;
+       import org.apache.royale.style.stylebeads.states.HoverState;
+       import org.apache.royale.style.stylebeads.states.attribute.DataState;
+       import org.apache.royale.style.stylebeads.typography.FontSmoothing;
+       import org.apache.royale.style.support.Icons;
+       import org.apache.royale.style.util.ThemeManager;
+       import org.apache.royale.style.stylebeads.background.BackgroundColor;
+       import org.apache.royale.style.stylebeads.typography.FontSize;
+       import org.apache.royale.style.stylebeads.typography.TextColor;
+       import org.apache.royale.style.stylebeads.typography.FontWeight;
+       import org.apache.royale.style.stylebeads.border.Border;
+       import org.apache.royale.style.stylebeads.spacing.Padding;
+
+       
+       
+       public class ToastSkin extends StyleSkin implements IToastSkin
+       {
+               
+               //distance from bottom that toast should pop-up to.
+               public static const arrivalOffset:uint = 30;
+               
+               private static const inAnimationName:String = 'toast-fadein';
+               private static const outAnimationName:String = 'toast-fadeout';
+               public static function getAnimation(out:Boolean):StyleBeadBase{
+                       var result:StyleBeadBase;
+                       var durationMillisecs:uint = 500;
+                       var name:String = out ? outAnimationName : 
inAnimationName;
+                       if (AnimationManager.has(name)) {
+                               //trace('optimized animation route',name)
+                               return new Animation(name + " " + 
durationMillisecs + "ms");
+                       }
+                       //trace('creating animation route',name)
+                       //otherwise create CustomAnimation, which registers it:
+                       if (out) {
+                               result = new CustomAnimation(name,[
+                                       'from {bottom: '+arrivalOffset+'px; 
opacity: 1; visibility: visible;}',
+                                       'to {bottom: 0px; opacity: 0; 
visibility: hidden;}'
+                               ],durationMillisecs);
+                       } else {
+                               //in
+                               result = new CustomAnimation(name,[
+                                       'from {bottom: 0; opacity: 0; 
visibility: visible; }',
+                                       'to {bottom: '+arrivalOffset+'px; 
opacity: 1; visibility: visible; }'
+                               ],durationMillisecs);
+                       }
+                       return result;
+               }
+               
+               public function ToastSkin()
+               {
+                       super();
+               }
+               
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Toast
+                */
+               private function get host():Toast
+               {
+                       return _strand as Toast;
+               }
+               override public function set strand(value:IStrand):void
+               {
+                       super.strand = value;
+                       applyStyles();
+               }
+
+               private function 
getBackgroundShade(colorSet:ThemeColorSet,colorState:String):ColorSwatch{
+                       var shade:uint = 500;
+                       return colorSet.getSwatch(colorState,shade);
+               }
+               
+               private function getHostFlavorColor():String{
+                       var hostFlavor:String = host.flavor;
+                       //normalize any 'specific' variations:
+                       switch(hostFlavor) {
+                               case 'negative':
+                                       hostFlavor = 'error';
+                                       break;
+                               case 'positive':
+                                       hostFlavor = 'success';
+                                       break;
+                               default:
+                       }
+                       return hostFlavor || ThemeColorSet.NEUTRAL;
+               }
+               
+               private function createToastStyles():void
+               {
+                       var multiplier:Number = getMultiplier();
+                       var colorState:String = getHostFlavorColor();
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet ;
+                       var backgroundColor:ColorSwatch = 
getBackgroundShade(colorSet,colorState);
+                       var padding:Padding = new 
Padding(computeSize(multiplier * 4, host.unit), host.unit);
+                       padding.right = padding.left = computeSize(8 * 
multiplier,padding.unit);
+                       var toastStyles:Array = [
+                               new Display('inline-flex'),
+                               /*new FlexDirection('row'),*/ //this is the 
default anyway
+                               new AlignItems('stretch'), // or new 
AlignItems('center')
+                               new BorderRadius(computeSize(4 * multiplier, 
host.unit)),
+                               padding,
+                               new FontSmoothing('antialiased'),
+                               new BackgroundColor(backgroundColor)
+                       ];
+                       var textStyles:Array = [
+                               new FontSize(/*computeSize(14 * multiplier, 
host.unit)*/host.size || 'base'),
+                               new FontWeight(700),
+                               new 
TextColor(colorSet.getContrastSwatch(backgroundColor))
+                       ];
+                       _toastStyles = toastStyles.concat(textStyles);
+               }
+               
+               private var _toastStyles:Array;
+               public function get toastContentStyles():Array
+               {
+                       if(!_toastStyles)
+                               createToastStyles();
+                       return _toastStyles;
+               }
+               
+               private function createBodyStyles():void
+               {
+                       var multiplier:Number = getMultiplier();
+                       var padding:Padding = new Padding(null, host.unit);
+                       padding.right = computeSize(8 * 
multiplier,padding.unit);
+                       var styles:Array = [
+                               padding,
+                               new Display('inline-flex'),
+                               new AlignItems('center')
+                       ];
+                       _bodyStyles = styles;
+               }
+               
+               private var _bodyStyles:Array;
+               public function get toastBodyStyles():Array
+               {
+                       if(!_bodyStyles)
+                               createBodyStyles();
+                       return _bodyStyles;
+               }
+               
+               private function createTextLayoutStyles():void{
+                       var multiplier:Number = getMultiplier();
+                       var padding:Padding = new 
Padding(computeSize(multiplier * 2, host.unit), host.unit);
+                       //padding.right = padding.left = computeSize(8 * 
multiplier,host.unit);
+                       padding.inline = computeSize(8 * multiplier,host.unit);
+                       _textLayoutStyles = [
+                                       new Display('inline-block'),
+                                       padding
+                       ];
+               }
+               
+               private var _textLayoutStyles:Array;
+               public function get textLayoutStyles():Array{
+                       if(!_textLayoutStyles)
+                               createTextLayoutStyles();
+                       return _textLayoutStyles;
+               }
+               
+               private function applyStyles():void
+               {
+                       var inAnimation:StyleBeadBase = getAnimation(false);
+                       var outAnimation:StyleBeadBase = getAnimation(true);
+                       var toastContainerStyles:Array = [
+                                       new UserSelect('none'),
+                                       new Position('fixed'),
+                                       new Bottom(arrivalOffset+'px'),
+                                       new WidthStyle('100%'),
+                                       new Display('flex'),
+                                       new AlignItems('center'),
+                                       new JustifyContent('center'),
+                                       new ZIndex(100),
+                                       new DataState('showing', [
+                                               inAnimation
+                                       ]),
+                                       new DataState('hiding', [
+                                               outAnimation
+                                       ])
+                       ];
+                       _styles = toastContainerStyles;
+                       host.setStyles(_styles, true);
+                       COMPILE::JS{
+                               host.element.addEventListener('animationend', 
onAnimationEnded);
+                       }
+               }
+               
+               private function onAnimationEnded(e:Object):void{
+                       switch(e.animationName) {
+                               case inAnimationName:
+                                       host.afterShow();
+                                       break;
+                               case outAnimationName:
+                                       host.afterHide();
+                                       break;
+                       }
+               }
+               
+               private function getMultiplier():Number
+               {
+                       switch(host.size)
+                       {
+                               case "xs":
+                                       return 0.6;
+                               case "sm":
+                                       return 0.8;
+                               case "md":
+                                       return 1;
+                               case "lg":
+                                       return 1.2;
+                               case "xl":
+                                       return 1.4;
+                               default:
+                                       return 1;
+                       }
+               }
+               
+               private function createButtonsLayoutStyles():void
+               {
+                       var padding:Padding = new Padding(null,host.unit);
+                       var multiplier:Number = getMultiplier();
+                       padding.left = computeSize(5 * multiplier,host.unit);
+                       var colorState:String = getHostFlavorColor();
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.getTheme(host.theme).themeColorSet;
+                       //we need a contrast with the background color
+                       var borderLineColor:ColorSwatch = 
colorSet.getContrastSwatch(getBackgroundShade(colorSet,colorState)).getVariant(NaN,80);
+                       var border:Border = new 
Border(borderLineColor.toString(),'none',computeSize(multiplier,host.unit),null,host.unit);
+                       border.leftStyle = 'solid';
+                       _buttonsLayoutStyles = [
+                               new Display('inline-flex'),
+                               padding,
+                               border,
+                               new AlignItems('center'),
+                               new JustifyContent('center')
+                       ];
+               }
+               
+               private var _buttonsLayoutStyles:Array;
+               public function get buttonsLayoutStyles():Array
+               {
+                       if(!_buttonsLayoutStyles)
+                               createButtonsLayoutStyles();
+                       return _buttonsLayoutStyles;
+               }
+               
+               private function getButtonHoverColor():BackgroundColor{
+                       var colorState:String = getHostFlavorColor();
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet ;
+                       var backgroundColor:ColorSwatch = 
getBackgroundShade(colorSet,colorState);
+                       return new 
BackgroundColor(colorSet.getContrastSwatch(backgroundColor).getVariant(NaN,20));
+               }
+               
+               private function createCloseButton():void{
+                       var multiplier:Number = getMultiplier();
+                       var closeButton:Button = new Button();
+                       var dimension:String = computeSize(20 * multiplier, 
host.unit)
+                       closeButton.setStyles([
+                               new WidthStyle(dimension),
+                               new HeightStyle(dimension),
+                               new Display('flex'),
+                               new AlignItems('center'),
+                               new JustifyContent('center'),
+                               new BackgroundColor('transparent'),
+                               new TextColor('inherit'),
+                               new BorderRadius('full'),
+                               new Transition(),
+                               new HoverState([
+                                       getButtonHoverColor()
+                               ])
+                       ])
+                       var icon:Icon = Icons.cross_Small();
+               
+                       icon.setStyles([
+                                       new Flex(1)
+                       ])
+                       closeButton.addElement(icon);
+                       _closeButton = closeButton;
+               }
+               
+               private var _closeButton:Button;
+               public function getCloseButton():IStyleUIBase{
+                       if (!_closeButton)
+                               createCloseButton();
+                       return _closeButton;
+               }
+               
+               public function getActionButton(action:String):IStyleUIBase{
+                       var button:Button = new Button();
+                       COMPILE::JS{
+                               button.element.textContent = action;
+                       }
+                       var multiplier:Number = getMultiplier();
+                       var padding:Padding = new 
Padding(computeSize(multiplier * 2, host.unit), host.unit);
+                       padding.inline = computeSize(8 * multiplier,host.unit);
+                       button.setStyles([
+                               new BackgroundColor('transparent'),
+                               padding,
+                               new BorderRadius('full'),
+                               new TextColor('inherit'), //button natively has 
its own text styles so we need to force inherit here to share our text styling
+                               new FontSize('inherit'),
+                               new FontWeight('inherit'),
+                               new Transition(),
+                               new HoverState([
+                                       getButtonHoverColor()
+                               ])
+                       ]);
+                       return button;
+               }
+               
+               public function getIcon(flavor:String):IStyleUIBase {
+                       var icon:Icon;
+                       switch(flavor) {
+                               case "error":
+                               case "warning":
+                               case "negative":
+                                       icon = Icons.alert_medium();
+                                       break;
+                               case "positive":
+                               case "success":
+                                       icon = Icons.success_medium();
+                                       break;
+                               case "info":
+                                       icon = Icons.info_medium();
+                                       break;
+                               default:
+                                       icon = null
+                       }
+                       
+                       if (icon) {
+                               var multiplier:Number = getMultiplier();
+                               var dimension:String = computeSize(20 * 
multiplier, host.unit);
+                               icon.setStyles([
+                                               new WidthStyle(dimension),
+                                               new HeightStyle(dimension)
+                               ])
+                       }
+                       return icon;
+               }
+       }
+}
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
index fff2a1d14d..39bae98425 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
@@ -48,21 +48,21 @@ package org.apache.royale.style.stylebeads.anim
 }
  */
 
-               override public function set value(value:*):void
+               override public function set value(v:*):void
                {
                        assert(
-                               isVar(value) || 
["spin","ping","pulse","bounce","none"].indexOf(value) != -1,
-                               "animation only accepts 'spin', 'ping', 
'pulse', 'bounce', or a CSS variable referencing a valid animation"
+                               isVar(v) || v == "none" || (v is String && 
v.length > 0),
+                               "animation only accepts a valid animation name, 
'none', or a CSS variable referencing an animation"
                                );
-                       calculatedRuleValue = calculatedSelector = _value = 
value;
-                       if(isVar(value))
+                       calculatedRuleValue = calculatedSelector = _value = v;
+                       if(isVar(v))
                        {
-                               calculatedRuleValue = fromVar(value);
+                               calculatedRuleValue = fromVar(v);
                        }
                        else
                        {
                                var theme:StyleTheme = 
ThemeManager.instance.activeTheme;
-                               switch(value)
+                               switch(v)
                                {
                                        case "spin":
                                                calculatedRuleValue = 
theme.animateSpin;
@@ -80,6 +80,6 @@ package org.apache.royale.style.stylebeads.anim
                                                break;
                                }
                        }
-               }               
+               }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationDuration.as
similarity index 59%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationDuration.as
index 4b2d978cb8..2945d35a69 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationDuration.as
@@ -16,17 +16,28 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.layout
+package org.apache.royale.style.stylebeads.anim
 {
        import org.apache.royale.style.stylebeads.LeafStyleBase;
        import org.apache.royale.debugging.assert;
+       import org.apache.royale.style.util.ThemeManager;
 
-       public class InsetBlockEnd extends InsetBase
+       public class AnimationDuration extends LeafStyleBase
        {
-               public function InsetBlockEnd()
+               public function AnimationDuration(value:* = null)
                {
-                       super("inset-be", "inset-block-end");
+                       super("duration", "animation-duration", value);
                }
 
+               override public function set value(value:*):void
+               {
+                       _value = value;
+                       assert(value == "default" || isVar(value) || 
(isInt(value) && value >= 0), "animation-duration only accepts valid CSS 
variables or non-negative integers representing milliseconds");
+                       calculatedSelector = value;
+                       if(value == "default")
+                               calculatedRuleValue = 
ThemeManager.instance.activeTheme.defaultTransitionDuration;
+                       else
+                               calculatedRuleValue = isInt(value) ? value + 
"ms" : fromVar(value);
+               }
        }
-}
\ No newline at end of file
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationIterationCount.as
similarity index 62%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationIterationCount.as
index 9428d3c829..79df3749b8 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationIterationCount.as
@@ -16,17 +16,31 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.layout
+package org.apache.royale.style.stylebeads.anim
 {
        import org.apache.royale.style.stylebeads.LeafStyleBase;
        import org.apache.royale.debugging.assert;
 
-       public class InsetBlockStart extends InsetBase
+       public class AnimationIterationCount extends LeafStyleBase
        {
-               public function InsetBlockStart()
+               public function AnimationIterationCount(value:* = null)
                {
-                       super("inset-bs", "inset-block-start");
+                       super("iteration", "animation-iteration-count", value);
                }
 
+               override public function get value():*
+               {
+                       return _value;
+               }
+
+               override public function set value(value:*):void
+               {
+                       assert(isVar(value) || value == "infinite" || 
(isInt(value) && value >= 0), "animation-iteration-count only accepts 
'infinite', a non-negative integer, or a CSS variable");
+                       calculatedRuleValue = calculatedSelector = _value = 
value;
+                       if(isVar(value))
+                       {
+                               calculatedRuleValue = fromVar(value);
+                       }
+               }
        }
-}
\ No newline at end of file
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationTimingFunction.as
similarity index 50%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationTimingFunction.as
index fff2a1d14d..e209841e20 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Animation.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/AnimationTimingFunction.as
@@ -19,67 +19,47 @@
 package org.apache.royale.style.stylebeads.anim
 {
        import org.apache.royale.style.stylebeads.LeafStyleBase;
-       import org.apache.royale.debugging.assert;
        import org.apache.royale.style.util.StyleTheme;
        import org.apache.royale.style.util.ThemeManager;
+       import org.apache.royale.style.util.CSSLookup;
+       import org.apache.royale.debugging.assert;
 
-       public class Animation extends LeafStyleBase
+       public class AnimationTimingFunction extends LeafStyleBase
        {
-               public function Animation(value:* = null)
+               public function AnimationTimingFunction(value:* = null)
                {
-                       super("animate", "animation", value);
+                       super("ease", "animation-timing-function", value);
                }
-
-// need to figure out how to register keyframes, etc.
-
-//animate-bounce       
-//animation: var(--animate-bounce); /* bounce 1s infinite */
-
-/**
-@keyframes bounce {
-  0%, 100% {
-    transform: translateY(-25%);
-    animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
-  }
-  50% {
-    transform: none;
-    animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
-  }
-}
- */
-
                override public function set value(value:*):void
                {
-                       assert(
-                               isVar(value) || 
["spin","ping","pulse","bounce","none"].indexOf(value) != -1,
-                               "animation only accepts 'spin', 'ping', 
'pulse', 'bounce', or a CSS variable referencing a valid animation"
-                               );
-                       calculatedRuleValue = calculatedSelector = _value = 
value;
-                       if(isVar(value))
-                       {
-                               calculatedRuleValue = fromVar(value);
-                       }
-                       else
+                       _value = value;
+                       var ruleValue:String = value;
+                       var selectorValue:String = value;
+                       var theme:StyleTheme = 
ThemeManager.instance.activeTheme;
+                       switch(value)
                        {
-                               var theme:StyleTheme = 
ThemeManager.instance.activeTheme;
-                               switch(value)
-                               {
-                                       case "spin":
-                                               calculatedRuleValue = 
theme.animateSpin;
-                                               break;
-                                       case "ping":
-                                               calculatedRuleValue = 
theme.animatePing;
-                                               break;
-                                       case "pulse":
-                                               calculatedRuleValue = 
theme.animatePulse;
-                                               break;
-                                       case "bounce":
-                                               calculatedRuleValue = 
theme.animateBounce;
-                                               break;
-                                       case "none":
-                                               break;
-                               }
+                               case "default":
+                                       ruleValue = 
theme.defaultTransitionTimingFunction;
+                                       break;
+                               case "in":
+                                       ruleValue = theme.easeIn;
+                                       break;
+                               case "out":
+                                       ruleValue = theme.easeOut;
+                                       break;
+                               case "in-out":
+                                       ruleValue = theme.easeInOut;
+                                       break;
+                               case "linear":
+                               case "initial":
+                                       break;
+                               default:
+                                       ruleValue = 
CSSLookup.getProperty(value);
+                                       break;
                        }
-               }               
+                       assert(ruleValue, "animation-timing-function only 
accepts 'linear', 'in', 'out', 'in-out', 'initial', or a valid CSS timing 
function value");
+                       calculatedSelector = selectorValue;
+                       calculatedRuleValue = ruleValue;
+               }
        }
-}
\ No newline at end of file
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/CustomAnimation.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/CustomAnimation.as
new file mode 100644
index 0000000000..5ab312324c
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/CustomAnimation.as
@@ -0,0 +1,105 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.style.stylebeads.anim
+{
+       import org.apache.royale.style.stylebeads.CompositeStyle;
+
+       public class CustomAnimation extends CompositeStyle
+       {
+               public function CustomAnimation(name:String = 
null,keyframes:Array = null,duration:Object = 'default',timingFunction:String = 
'default',iterationCount:String = null)
+               {
+                       super();
+                       _nameStyle = new Keyframes(name,keyframes);
+                       _timingStyle = new 
AnimationTimingFunction(timingFunction);
+                       _durationStyle = new AnimationDuration(duration);
+                       styles = [
+                               _nameStyle,
+                               _timingStyle,
+                               _durationStyle
+                       ];
+                       if (iterationCount)
+                       {
+                               this.iterationCount = iterationCount;
+                       }
+               }
+
+               private var _nameStyle:Keyframes;
+               private var _timingStyle:AnimationTimingFunction;
+               private var _durationStyle:AnimationDuration;
+               private var _iterationCountStyle:AnimationIterationCount;
+
+               public function get name():String
+               {
+                       return _nameStyle.value;
+               }
+
+               public function set name(value:String):void
+               {
+                       _nameStyle.value = value;
+               }
+
+               public function get keyframes():Array
+               {
+                       return _nameStyle.keyframes;
+               }
+
+               public function set keyframes(value:Array):void
+               {
+                       _nameStyle.keyframes = value;
+               }
+
+               public function get timingFunction():String
+               {
+                       return _timingStyle.value;
+               }
+
+               public function set timingFunction(value:String):void
+               {
+                       _timingStyle.value = value;
+               }
+
+               public function get duration():*
+               {
+                       return _durationStyle.value;
+               }
+
+               public function set duration(value:*):void
+               {
+                       _durationStyle.value = value;
+               }
+
+               public function get iterationCount():String
+               {
+                       return _iterationCountStyle ? 
_iterationCountStyle.value : null;
+               }
+
+               public function set iterationCount(value:String):void
+               {
+                       if (!_iterationCountStyle)
+                       {
+                               _iterationCountStyle = new 
AnimationIterationCount(value);
+                               addStyleBead(_iterationCountStyle);
+                       }
+                       else
+                       {
+                               _iterationCountStyle.value = value;
+                       }
+               }
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Keyframes.as
similarity index 54%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Keyframes.as
index 4b2d978cb8..2792189ea5 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/Keyframes.as
@@ -16,17 +16,49 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.layout
+package org.apache.royale.style.stylebeads.anim
 {
        import org.apache.royale.style.stylebeads.LeafStyleBase;
-       import org.apache.royale.debugging.assert;
+       import org.apache.royale.style.util.AnimationManager;
 
-       public class InsetBlockEnd extends InsetBase
+       public class Keyframes extends LeafStyleBase
        {
-               public function InsetBlockEnd()
+               public function Keyframes(name:String = null, value:Array = 
null)
                {
-                       super("inset-be", "inset-block-end");
+                       _keyframes = value;
+                       super("keyframes", "animation-name", name);
                }
 
+               private var _keyframes:Array;
+
+               public function get keyframes():Array
+               {
+                       return _keyframes;
+               }
+
+               public function set keyframes(value:Array):void
+               {
+                       _keyframes = value;
+                       if (_value && _keyframes)
+                       {
+                               AnimationManager.registerKeyframes(_value, 
_keyframes);
+                       }
+               }
+
+               override public function get value():*
+               {
+                       return _value;
+               }
+
+               override public function set value(value:*):void
+               {
+                       _value = value;
+                       calculatedSelector = _value;
+                       calculatedRuleValue = _value;
+                       if (_value && _keyframes)
+                       {
+                               AnimationManager.registerKeyframes(_value, 
_keyframes);
+                       }
+               }
        }
-}
\ No newline at end of file
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Bottom.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Bottom.as
index ae272f81fb..5d32f7d57b 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Bottom.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Bottom.as
@@ -20,9 +20,9 @@ package org.apache.royale.style.stylebeads.layout
 {
        public class Bottom extends InsetBase
        {
-               public function Bottom()
+               public function Bottom(value:* = null)
                {
-                       super("bottom", "bottom");
+                       super("bottom", "bottom", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Inset.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Inset.as
index 77b52a3305..effbe92940 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Inset.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Inset.as
@@ -23,9 +23,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class Inset extends InsetBase
        {
-               public function Inset()
+               public function Inset(value:* = null)
                {
-                       super("inset", "inset");
+                       super("inset", "inset", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBase.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBase.as
index 9c688b008b..dcaede4639 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBase.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBase.as
@@ -30,10 +30,12 @@ package org.apache.royale.style.stylebeads.layout
                private var savedPrefix:String;
                override public function set value(value:*):void
                {
+                       _value = value;
                        var isNum:Boolean = parseFloat(value) == value;
                        var isInt:Boolean = int(value) == value;
                        var parseNum:Number = parseFloat(value);
                        var isNegative:Boolean = parseNum < 0;
+
                        if(isNegative)
                        {
                                if(!savedPrefix)
@@ -55,12 +57,9 @@ package org.apache.royale.style.stylebeads.layout
                        {
                                calculatedSelector = sanitizeSelector(value);
                                calculatedRuleValue = value;
+                               if(value == "none")
+                                       calculatedSelector = "hidden";
                        }
-                       // 
assert(["inline","block","inline-block","flow-root","flex","inline-flex","grid","inline-grid","contents","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","list-item","none"].indexOf(value)
 >= 0, "Invalid value for display: " + value);
-                       _value = value;
-                       calculatedRuleValue = calculatedSelector = value;
-                       if(value == "none")
-                               calculatedSelector = "hidden";
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
index 2c5260018b..f8314e8137 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlock.as
@@ -23,9 +23,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class InsetBlock extends InsetBase
        {
-               public function InsetBlock()
+               public function InsetBlock(value:* = null)
                {
-                       super("inset-y", "inset-block");
+                       super("inset-y", "inset-block", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
index 4b2d978cb8..6a60eb83da 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockEnd.as
@@ -23,9 +23,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class InsetBlockEnd extends InsetBase
        {
-               public function InsetBlockEnd()
+               public function InsetBlockEnd(value:* = null)
                {
-                       super("inset-be", "inset-block-end");
+                       super("inset-block-end", "inset-block-end", value);
                }
 
        }
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
index 9428d3c829..0c22d15ac8 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
@@ -23,9 +23,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class InsetBlockStart extends InsetBase
        {
-               public function InsetBlockStart()
+               public function InsetBlockStart(value:* = null)
                {
-                       super("inset-bs", "inset-block-start");
+                       super("inset-block-start", "inset-block-start", value);
                }
 
        }
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineEnd.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineEnd.as
index daf90c196d..ebd372dcde 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineEnd.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineEnd.as
@@ -20,9 +20,9 @@ package org.apache.royale.style.stylebeads.layout
 {
        public class InsetInlineEnd extends InsetBase
        {
-               public function InsetInlineEnd()
+               public function InsetInlineEnd(value:* = null)
                {
-                       super("inset-e", "inset-inline-end");
+                       super("inset-inline-end", "inset-inline-end", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineStart.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineStart.as
index 9445e67fd4..03205315b6 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineStart.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetInlineStart.as
@@ -23,9 +23,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class InsetInlineStart extends InsetBase
        {
-               public function InsetInlineStart()
+               public function InsetInlineStart(value:* = null)
                {
-                       super("inset-s", "inset-inline-start");
+                       super("inset-inline-start", "inset-inline-start", 
value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Left.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Left.as
index 1943d10522..0ed0885b7d 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Left.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Left.as
@@ -20,9 +20,9 @@ package org.apache.royale.style.stylebeads.layout
 {
        public class Left extends InsetBase
        {
-               public function Left()
+               public function Left(value:* = null)
                {
-                       super("left", "left");
+                       super("left", "left", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Right.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Right.as
index b023a5c522..187711cbef 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Right.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Right.as
@@ -22,9 +22,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class Right extends InsetBase
        {
-               public function Right()
+               public function Right(value:* = null)
                {
-                       super("right", "right");
+                       super("right", "right", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Top.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Top.as
index db803e5df7..fd3f2de67a 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Top.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/Top.as
@@ -22,9 +22,9 @@ package org.apache.royale.style.stylebeads.layout
 
        public class Top extends InsetBase
        {
-               public function Top()
+               public function Top(value:* = null)
                {
-                       super("top", "top");
+                       super("top", "top", value);
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/states/attribute/NotDataState.as
similarity index 59%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/states/attribute/NotDataState.as
index 9428d3c829..a7ed5fdde4 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/layout/InsetBlockStart.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/states/attribute/NotDataState.as
@@ -16,17 +16,35 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.layout
+package org.apache.royale.style.stylebeads.states.attribute
 {
-       import org.apache.royale.style.stylebeads.LeafStyleBase;
-       import org.apache.royale.debugging.assert;
+       import org.apache.royale.style.stylebeads.states.NotState;
 
-       public class InsetBlockStart extends InsetBase
+       /**
+        * NotDataState is a decorator that adds a :not([data-attribute]) 
pseudo-class to the rule.
+        */
+       public class NotDataState extends NotState
        {
-               public function InsetBlockStart()
+               public function NotDataState(type:String = null, styles:Array = 
null)
                {
-                       super("inset-bs", "inset-block-start");
+                       super(null, styles);
+                       if(type)
+                       {
+                               dataType = type;
+                       }
                }
+               private var _dataType:String;
 
+               public function get dataType():String
+               {
+                       return _dataType;
+               }
+
+               public function set dataType(value:String):void
+               {
+                       _dataType = value;
+                       ruleDecorator = "[data-" + value + "]";
+                       selectorDecorator = "not-data-" + value + ":";
+               }
        }
-}
\ No newline at end of file
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/support/Icons.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/support/Icons.as
new file mode 100644
index 0000000000..ea9100260b
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/support/Icons.as
@@ -0,0 +1,92 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.royale.style.support
+{
+       import org.apache.royale.style.Icon;
+       
+
+       /**
+        * The Icons class supports commonly used icons
+        *  
+        * This file includes derived work based on Adobe Spectrum Icons,
+        * licensed under the Apache License, Version 2.0.
+        *
+        *
+        *  @langversion 3.0
+        *  @playerversion Flash 10.2
+        *  @playerversion AIR 2.6
+        *  @productversion Royale 1.0
+        *  
+        *  @royalesuppressexport
+        */
+       public class Icons 
+       {
+               /**
+                *  constructor.
+                *
+                *  @private
+                */
+               private function Icons()
+               {
+                       super();
+               }
+               
+               /**
+                * @royalesuppressexport
+                */
+               public static function cross_Small():Icon{
+                       if (!Icon.isRegistered('support_icons_cross_small')) { 
+                               Icon.registerIcon('support_icons_cross_small', 
<svg viewBox="0 0 20 20" fill="currentColor" stroke="none"><path d="M13.317 
12.433L10.884 10l2.433-2.433a.625.625 0 1 0-.884-.884L10 9.116 7.567 
6.683a.625.625 0 1 0-.884.884L9.116 10 6.683 12.433a.625.625 0 1 0 .884.884L10 
10.884l2.433 2.433a.625.625 0 0 0 .884-.884z" stroke-linecap="round" 
stroke-linejoin="round"/></svg>);
+                       }
+                       return new Icon('support_icons_cross_small');
+               }
+               
+               /**
+                * @royalesuppressexport
+                */
+               public static function info_medium():Icon{
+                       if (!Icon.isRegistered('support_icons_info_medium')) {
+                               Icon.registerIcon('support_icons_info_medium', 
<svg viewBox="0 0 20 20" fill="currentColor" stroke="none"><path d="M11 3a8 8 0 
1 0 8 8 8 8 0 0 0-8-8zm-.15 2.15a1.359 1.359 0 0 1 1.431 
1.283q.004.064.001.129A1.332 1.332 0 0 1 10.85 7.994a1.353 1.353 0 0 
1-1.432-1.433 1.359 1.359 0 0 1 1.304-1.412q.064-.002.128.001zM13 15.5a.5.5 0 0 
1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5H10V11h-.5a.5.5 0 0 
1-.5-.5v-1a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5V14h.5a.5.5 0 0 1 .5.5z"    
stroke-linecap="rou [...]
+                       }
+                       return new Icon('support_icons_info_medium');
+               }
+               
+               /**
+                * @royalesuppressexport
+                */
+               public static function alert_medium():Icon{
+                       if (!Icon.isRegistered('support_icons_alert_medium')) {
+                               Icon.registerIcon('support_icons_alert_medium', 
<svg viewBox="0 0 20 20" fill="currentColor" stroke="none"><path d="M10.564 
3.289L2.2 18.256A.5.5 0 0 0 2.636 19h16.728a.5.5 0 0 0 .436-.744L11.436 
3.289a.5.5 0 0 0-.872 0zM12 16.75a.25.25 0 0 1-.25.25h-1.5a.25.25 0 0 
1-.25-.25v-1.5a.25.25 0 0 1 .25-.25h1.5a.25.25 0 0 1 .25.25zm0-3a.25.25 0 0 
1-.25.25h-1.5a.25.25 0 0 1-.25-.25v-6a.25.25 0 0 1 .25-.25h1.5a.25.25 0 0 1 
.25.25z" stroke-linecap="round" stroke-linejoin="round"/></svg>);
+                       }
+                       return new Icon('support_icons_alert_medium');
+               }
+               
+               /**
+                * @royalesuppressexport
+                */
+               public static function success_medium():Icon{
+                       if (!Icon.isRegistered('support_icons_success_medium')) 
{
+                               
Icon.registerIcon('support_icons_success_medium', <svg viewBox="0 0 20 20" 
fill="currentColor" stroke="none"><path d="M11 3A8 8 0 1 0 19 11A8 8 0 0 0 11 
3M16.333 7.54L10.009 15.67A.6.6 0 0 1 9.572 15.9H9.535A.6.6 0 0 1 9.11 
15.724L5.217 11.824A.6.6 0 0 1 5.217 10.975L5.88 10.312A.6.6 0 0 1 6.728 
10.312L9.4 12.991L14.656 6.237A.6.6 0 0 1 15.499 6.137L16.227 6.703A.6.6 0 0 1 
16.333 7.54Z" stroke-linecap="round" stroke-linejoin="round"/></svg>);
+                       }
+                       return new Icon('support_icons_success_medium');
+               }
+               
+               
+       }
+}

Reply via email to