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 208b2661d6 getting initial Tooltip in. TooltipBead will be next.
208b2661d6 is described below

commit 208b2661d621c7832d25da74da01ead9db93bb3f
Author: greg-dove <[email protected]>
AuthorDate: Thu Apr 23 16:50:08 2026 +1200

    getting initial Tooltip in. TooltipBead will be next.
---
 .../projects/Style/src/main/resources/defaults.css |   3 +
 .../Style/src/main/resources/style-manifest.xml    |   3 +
 .../main/royale/org/apache/royale/style/Tooltip.as | 265 ++++++++++++++++++
 .../TransitionDuration.as => const/AppLayers.as}   |  31 +--
 .../ITooltipSkin.as}                               |  32 +--
 .../org/apache/royale/style/skins/TooltipSkin.as   | 295 +++++++++++++++++++++
 .../royale/style/stylebeads/anim/Animation.as      |   1 +
 .../style/stylebeads/anim/TransitionDuration.as    |  50 +++-
 .../style/stylebeads/anim/TransitionProperty.as    |   6 +
 .../stylebeads/anim/TransitionTimingFunction.as    |  46 +++-
 .../royale/style/stylebeads/transform/Transform.as |   6 +
 .../org/apache/royale/style/support/Icons.as       |  12 +
 12 files changed, 692 insertions(+), 58 deletions(-)

diff --git a/frameworks/projects/Style/src/main/resources/defaults.css 
b/frameworks/projects/Style/src/main/resources/defaults.css
index 457bc2bdef..d244396ccb 100644
--- a/frameworks/projects/Style/src/main/resources/defaults.css
+++ b/frameworks/projects/Style/src/main/resources/defaults.css
@@ -231,3 +231,6 @@ Tree
 Toast {
        IStyleSkin: ClassReference("org.apache.royale.style.skins.ToastSkin");
 }
+Tooltip {
+       IStyleSkin: ClassReference("org.apache.royale.style.skins.TooltipSkin");
+}
diff --git a/frameworks/projects/Style/src/main/resources/style-manifest.xml 
b/frameworks/projects/Style/src/main/resources/style-manifest.xml
index 1f3957d317..1ce74e9a98 100644
--- a/frameworks/projects/Style/src/main/resources/style-manifest.xml
+++ b/frameworks/projects/Style/src/main/resources/style-manifest.xml
@@ -62,6 +62,7 @@
   <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="Tooltip" class="org.apache.royale.style.Tooltip"/>
   <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"/>
@@ -333,5 +334,7 @@
   <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"/>
+  <component id="TooltipSkin" 
class="org.apache.royale.style.skins.TooltipSkin"/>
+  <component id="ITooltipSkin" 
class="org.apache.royale.style.skins.ITooltipSkin"/>
 
 </componentPackage>
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Tooltip.as 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Tooltip.as
new file mode 100644
index 0000000000..ca3c5d4ac3
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Tooltip.as
@@ -0,0 +1,265 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.debugging.assert;
+  import org.apache.royale.style.elements.Div;
+  import org.apache.royale.style.elements.Span;
+  import org.apache.royale.style.skins.ITooltipSkin;
+  
+  COMPILE::JS {
+    import org.apache.royale.core.WrappedHTMLElement;
+  }
+  
+  public class Tooltip extends StyleUIBase implements IHasLabel
+  {
+    
+    public function Tooltip()
+    {
+      super();
+    }
+  
+    private var _contentNode:Div;
+    /**
+     * The container node for the tooltip message
+     */
+    public function get contentNode():Div{
+      return _contentNode;
+    }
+
+    private var _labelNode:Span;
+    /**
+     * The label element within the content node
+     */
+    public function get labelNode():Span{
+      return _labelNode;
+    }
+
+    private var _tipNode:Span;
+    /**
+     * The tip (arrow) element
+     */
+    public function get tipNode():Span{
+      return _tipNode;
+    }
+
+    private var _text:String;
+
+    public function get text():String
+    {
+       return _text;
+    }
+
+    public function set text(value:String):void
+    {
+      if(_text != value){
+        _text = value;
+        if(_labelNode) _labelNode.text = value;
+      }
+    }
+
+    public function get label():String {
+      return text;
+    }
+    
+    public function set label(value:String):void {
+      text = value;
+    }
+
+    private var _flavor:String;
+
+    /**
+     * The flavor of the Tooltip
+     * One of info, positive and negative, success and error.
+     * To set the Tooltip to the default, specify an empty string
+     * for each of the known categories, an icon is shown by default, 
+     * unless the separate icon property is set to 'none'
+     */
+    public function get flavor():String
+    {
+       return _flavor;
+    }
+
+    [Inspectable(category="General", 
enumeration="info,positive,negative,success,error")]
+    public function set flavor(value:String):void
+    {
+      if(value != _flavor){
+        switch(value){
+          case "info":
+          case "positive":
+          case "negative":
+          case "success":
+          case "error":
+          case "":
+            break;
+          default:
+            throw new Error("Unknown flavor: " + value);
+        }
+        _flavor = value;
+        if (skin) {
+          updateFlavorIcon();
+        }
+      }
+    }
+    
+    
+    private var _icon:String = '';
+    /**
+     * Icon to display, which can override the default icon selected by 
'flavor'. One of: info, success, alert, help, none
+     * Default is no value.
+     * if not set, then the flavor will dictate a default icon. Otherwise, 
this setting takes precedence
+     */
+    public function get icon():String
+    {
+      return _icon;
+    }
+    
+    [Inspectable(category="General", 
enumeration="info,success,alert,help,none")]
+    public function set icon(value:String):void
+    {
+      value = value || '';
+      if (value != _icon) {
+        _icon = value;
+        if (skin) {
+          updateFlavorIcon();
+        }
+      }
+    }
+    
+
+    private var _flavorIcon:IStyleUIBase;
+
+    private function updateFlavorIcon():void{
+      if (_flavorIcon) {
+        _contentNode.removeElement(_flavorIcon);
+      }
+      var tooltipSkin:ITooltipSkin = skin as ITooltipSkin;
+      if (tooltipSkin) {
+        var flavor:String = _icon || _flavor;
+        _flavorIcon = tooltipSkin.getIcon(flavor);
+        if (_flavorIcon) {
+          _contentNode.addElementAt(_flavorIcon, 0);
+        }
+      }
+    }
+
+    private var _direction:String = 'top';
+
+    public function get direction():String
+    {
+       return _direction;
+    }
+
+    [Inspectable(category="General", enumeration="left,right,bottom,top", 
defaultValue="top")]
+    public function set direction(value:String):void
+    {
+      if (value == _direction) return;
+     /* if(_direction){
+        toggleAttribute("data-direction-" + _direction, false);
+      }*/
+      if(value){
+        switch(value){
+          case "left":
+          case "right":
+          case "bottom":
+          case "top":
+         //   toggleAttribute("data-direction-" + value, true);
+            break;
+          default:
+            throw new Error("Invalid direction: " + value);
+        }
+      }
+      _direction = value;
+      positionTip();
+    }
+
+    private var _tipPosition:String = "center";
+    /**
+     * The position of the tip within the tooltip
+     */
+    public function get tipPosition():String{
+       return _tipPosition;
+    }
+
+    [Inspectable(category="General", enumeration="start,end,center")]
+    public function set tipPosition(value:String):void{
+      if(value == _tipPosition){
+        return;
+      }
+      switch(value){
+        case "start":
+        case "end":
+        case "center":
+          _tipPosition = value;
+          break;
+        default:
+          _tipPosition = "center";
+          break;
+      }
+      positionTip();
+    }
+
+    private function positionTip():void{
+      if (skin) {
+        _tipNode.setStyles(( skin as ITooltipSkin).tipStyles, true);
+      }
+    }
+
+    private var _isOpen:Boolean;
+
+    public function get isOpen():Boolean
+    {
+       return _isOpen;
+    }
+
+    public function set isOpen(value:Boolean):void
+    {
+      if(value != !!_isOpen){
+        toggleAttribute("is-open", value);
+      }
+      _isOpen = value;
+    }
+
+    COMPILE::JS
+    override protected function createElement():WrappedHTMLElement{
+      var elem:WrappedHTMLElement = super.createElement();
+      _contentNode = new Div();
+      _labelNode = new Span();
+      if(_text) _labelNode.text = _text;
+      _contentNode.addElement(_labelNode);
+      _tipNode = new Span();
+      
+      elem.appendChild(_contentNode.element);
+      elem.appendChild(_tipNode.element);
+      return elem;
+    }
+
+    override protected function applySkin():void{
+      var tooltipSkin:ITooltipSkin = skin as ITooltipSkin;
+      assert(tooltipSkin is ITooltipSkin, "Tooltip requires a skin that 
implements ITooltipSkin");
+      
+      _contentNode.setStyles(tooltipSkin.tooltipContentStyles, true);
+      _tipNode.setStyles(tooltipSkin.tipStyles, true);
+      
+      updateFlavorIcon();
+      positionTip();
+    }
+  }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/const/AppLayers.as
similarity index 52%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/const/AppLayers.as
index 82f91d2b33..c02042f53c 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/const/AppLayers.as
@@ -16,29 +16,20 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.anim
+package org.apache.royale.style.const
 {
-       import org.apache.royale.style.stylebeads.LeafStyleBase;
-       import org.apache.royale.debugging.assert;
-       import org.apache.royale.style.util.CSSLookup;
-       import org.apache.royale.style.util.ThemeManager;
-
-       public class TransitionDuration extends LeafStyleBase
+       /**
+        * @royalesuppressexport
+        */
+       public class AppLayers
        {
-               public function TransitionDuration(value:* = null)
+               /**
+                * Static only
+                */
+               private function AppLayers()
                {
-                       super("duration", "transition-duration", value);
-               }
-
-               override public function set value(value:*):void
-               {
-                       _value = value;
-                       assert(value == "default" || isVar(value) || 
(isInt(value) && value >= 0), "transition-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);
+                       
                }
+               public static const TOOL_TIPS:uint = 4;
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ITooltipSkin.as
similarity index 51%
copy from 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
copy to 
frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ITooltipSkin.as
index 82f91d2b33..a540ba278d 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ITooltipSkin.as
@@ -16,29 +16,15 @@
 //  limitations under the License.
 //
 
////////////////////////////////////////////////////////////////////////////////
-package org.apache.royale.style.stylebeads.anim
+package org.apache.royale.style.skins
 {
-       import org.apache.royale.style.stylebeads.LeafStyleBase;
-       import org.apache.royale.debugging.assert;
-       import org.apache.royale.style.util.CSSLookup;
-       import org.apache.royale.style.util.ThemeManager;
-
-       public class TransitionDuration extends LeafStyleBase
+       import org.apache.royale.style.IStyleSkin;
+       import org.apache.royale.style.IStyleUIBase;
+       
+       public interface ITooltipSkin extends IStyleSkin
        {
-               public function TransitionDuration(value:* = null)
-               {
-                       super("duration", "transition-duration", value);
-               }
-
-               override public function set value(value:*):void
-               {
-                       _value = value;
-                       assert(value == "default" || isVar(value) || 
(isInt(value) && value >= 0), "transition-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);
-               }
+               function get tooltipContentStyles():Array;
+               function get tipStyles():Array;
+               function getIcon(flavor:String):IStyleUIBase;
        }
-}
\ No newline at end of file
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TooltipSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TooltipSkin.as
new file mode 100644
index 0000000000..705ed47666
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TooltipSkin.as
@@ -0,0 +1,295 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.core.IStrand;
+       import org.apache.royale.style.Icon;
+       import org.apache.royale.style.IStyleUIBase;
+       import org.apache.royale.style.StyleSkin;
+       import org.apache.royale.style.Tooltip;
+       import org.apache.royale.style.colors.ColorSwatch;
+       import org.apache.royale.style.colors.ThemeColorSet;
+       import org.apache.royale.style.stylebeads.anim.Transition;
+       import org.apache.royale.style.stylebeads.background.BackgroundColor;
+       import org.apache.royale.style.stylebeads.border.Border;
+       import org.apache.royale.style.stylebeads.border.BorderRadius;
+       import org.apache.royale.style.stylebeads.effects.OpacityStyle;
+       import org.apache.royale.style.stylebeads.flexgrid.AlignItems;
+       import org.apache.royale.style.stylebeads.flexgrid.Flex;
+       import org.apache.royale.style.stylebeads.flexgrid.Gap;
+       import org.apache.royale.style.stylebeads.interact.UserSelect;
+       import org.apache.royale.style.stylebeads.layout.Bottom;
+       import org.apache.royale.style.stylebeads.layout.Display;
+       import org.apache.royale.style.stylebeads.layout.Left;
+       import org.apache.royale.style.stylebeads.layout.Position;
+       import org.apache.royale.style.stylebeads.layout.Right;
+       import org.apache.royale.style.stylebeads.layout.Top;
+       import org.apache.royale.style.stylebeads.layout.Visibility;
+       import org.apache.royale.style.stylebeads.sizing.HeightStyle;
+       import org.apache.royale.style.stylebeads.sizing.MaxWidth;
+       import org.apache.royale.style.stylebeads.sizing.WidthStyle;
+       import org.apache.royale.style.stylebeads.spacing.Margin;
+       import org.apache.royale.style.stylebeads.spacing.Padding;
+       import 
org.apache.royale.style.stylebeads.states.attribute.AttributeState;
+       import org.apache.royale.style.stylebeads.transform.Transform;
+       import org.apache.royale.style.stylebeads.typography.FontSize;
+       import org.apache.royale.style.stylebeads.typography.FontWeight;
+       import org.apache.royale.style.stylebeads.typography.LineHeight;
+       import org.apache.royale.style.stylebeads.typography.OverflowWrap;
+       import org.apache.royale.style.stylebeads.typography.TextColor;
+       import org.apache.royale.style.stylebeads.typography.Whitespace;
+       import org.apache.royale.style.stylebeads.typography.WordBreak;
+       import org.apache.royale.style.support.Icons;
+       import org.apache.royale.style.util.ThemeManager;
+
+       public class TooltipSkin extends StyleSkin implements ITooltipSkin
+       {
+               public function TooltipSkin()
+               {
+                       super();
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Tooltip
+                */
+               private function get host():Tooltip
+               {
+                       return _strand as Tooltip;
+               }
+
+               override public function set strand(value:IStrand):void
+               {
+                       super.strand = value;
+                       applyStyles();
+               }
+               
+               //common reference values:
+               private static const inline_padding:uint = 10;
+               private static const block_padding:uint = 5;
+               private static const border_radius:uint = 4;
+               private static const nominal_font_size:uint = 12;
+               private static const nominal_icon_size:uint = 14;
+               private static const nominal_text_width:uint = 120;
+               private static const font_weight:uint = 400;
+               
+
+               private function applyStyles():void
+               {
+                       //transform 130ms ease-in-out, opacity 130ms 
ease-in-out, visibility 0ms linear 130ms;
+                       
+                       var transition:Transition = new Transition()
+                       transition.property = 'transform, opacity, visibility';
+                       
+                       transition.timingFunction 
='ease-in-out,ease-in-out,linear'
+                       
+                       //var multiplier:Number = getMultiplier();
+                       var styles:Array = [
+                               new Display('inline-flex'),
+                               new AlignItems('center'),
+                               new Position('relative'),
+                               new UserSelect('none'),
+                               transition,
+                               new Visibility('hidden'),
+                               new OpacityStyle(0),
+                               new AttributeState('is-open',[
+                                               new Visibility('visible'),
+                                               new OpacityStyle(100)
+                               ])
+                       ];
+                       host.setStyles(styles, true);
+               }
+
+               private function getHostFlavorColor():String
+               {
+                       var hostFlavor:String = host.flavor;
+                       switch(hostFlavor) {
+                               case 'negative':
+                                       hostFlavor = 'error';
+                                       break;
+                               case 'positive':
+                                       hostFlavor = 'success';
+                                       break;
+                               default:
+                       }
+                       return hostFlavor || ThemeColorSet.NEUTRAL;
+               }
+
+               private function getBackgroundShade(colorSet:ThemeColorSet, 
colorState:String):ColorSwatch
+               {
+                       var shade:uint = 700; // Tooltips are usually darker
+                       return colorSet.getSwatch(colorState, shade);
+               }
+
+               private function createContentStyles():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 * block_padding, host.unit), host.unit);
+                       padding.inline = computeSize(inline_padding * 
multiplier, host.unit);
+                       
+                       //we will use a smaller font size rather than the theme 
lookups.
+                       var textSizing:String = computeSize(nominal_font_size * 
multiplier, host.unit);
+
+                       var styles:Array = [
+                               new Display('inline-flex'),
+                               new AlignItems('flex-start'),
+                               new Gap(padding.inline), //make the gap the 
same as the inline padding
+                               new BorderRadius(computeSize(border_radius * 
multiplier, host.unit)),
+                               padding,
+                               new BackgroundColor(backgroundColor),
+                               new FontSize(textSizing),
+                               new LineHeight(textSizing),
+                               new FontWeight(font_weight),
+                               new Whitespace('pre-wrap'),
+                               new WordBreak('normal'),
+                               new OverflowWrap('anywhere'),
+                               new MaxWidth(computeSize((nominal_text_width + 
nominal_icon_size) * multiplier, host.unit)),
+                               new 
TextColor(colorSet.getContrastSwatch(backgroundColor))
+                       ];
+                       _contentStyles = styles;
+               }
+
+               private var _contentStyles:Array;
+               public function get tooltipContentStyles():Array
+               {
+                       if (!_contentStyles)
+                               createContentStyles();
+                       return _contentStyles;
+               }
+
+               public function get tipStyles():Array
+               {
+                       var unit:String = host.unit;
+                       // The tip (arrow) shares the background color of the 
content
+                       var colorState:String = getHostFlavorColor();
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
+                       var backgroundColor:ColorSwatch = 
getBackgroundShade(colorSet, colorState);
+                       var multiplier:Number = getMultiplier();
+                       var tipWidth:String = computeSize(border_radius * 
multiplier,host.unit);
+                       
+                       var border:Border = new 
Border('transparent','solid',tipWidth,'0',unit);
+                       border.topColor = backgroundColor.colorSpecifier;
+                       
+                       //location related:
+                       var locationStyles:Array = []
+                       var tipDirection:String = host.direction;
+                       var tipPosition:String = host.tipPosition;
+                       var margin:Margin = new Margin(null,unit);
+                       var transform:Transform = new Transform();
+                       locationStyles.push(margin);
+                       
+                       var sideLocation:String;
+                       if (tipPosition == 'center') {
+                               sideLocation = '50%';
+                       } else {
+                               var cornerExclusionZone:String = 
computeSize(border_radius * 1.5 * multiplier,unit);
+                               sideLocation = 'calc(' + (tipPosition == 
'start' ? '0% + ' : '100% - ') + cornerExclusionZone + ')';
+                       }
+
+                       switch(tipDirection) {
+                               case 'bottom':
+                                       margin.left = '-'+tipWidth;
+                                       locationStyles.push(new Bottom('100%'));
+                                       transform.rotate = '180deg';
+                                       locationStyles.push(transform);
+                                       //side location
+                                       locationStyles.push(new 
Left(sideLocation));
+                                       break;
+                               case 'left':
+                                       margin.top = '-'+tipWidth;
+                                       locationStyles.push(new Right('100%'));
+                                       transform.rotate = '90deg';
+                                       locationStyles.push(transform);
+                                       //side location
+                                       locationStyles.push(new 
Top(sideLocation));
+                                       break;
+                               case 'right':
+                                       margin.top = '-'+tipWidth;
+                                       locationStyles.push(new Left('100%'));
+                                       transform.rotate = '-90deg';    
+                                       locationStyles.push(transform);
+                                       //side location
+                                       locationStyles.push(new 
Top(sideLocation));
+                                       break;
+                               default:
+                                       margin.left = '-'+tipWidth;
+                                       locationStyles.push(new Top('100%'));
+                                       //side location
+                                       locationStyles.push(new 
Left(sideLocation));
+                       }
+                       
+                       return [
+                               new Position('absolute'),
+                                       new WidthStyle('0'),
+                                       new HeightStyle('0'),
+                                       border
+                               
+                       ].concat(locationStyles);
+               }
+
+               public function getIcon(flavor:String):IStyleUIBase
+               {
+                       var icon:Icon;
+                       switch(flavor) {
+                               case "error":
+                               case "negative":
+                                       icon = Icons.alert_medium();
+                                       break;
+                               case "success":
+                               case "positive":
+                                       icon = Icons.success_medium();
+                                       break;
+                               case "info":
+                                       icon = Icons.info_medium();
+                                       break;
+                               case "help":
+                                       icon = Icons.help_medium();
+                                       break;
+                               default:
+                                       icon = null;
+                       }
+                       
+                       if (icon) {
+                               var multiplier:Number = getMultiplier();
+                               var dimension:String = 
computeSize(nominal_icon_size * multiplier, host.unit);
+                               icon.setStyles([
+                                        new WidthStyle(dimension),
+                                        new HeightStyle(dimension),
+                                        new Flex('0 0 auto')
+                               ]);
+                       }
+                       return icon;
+               }
+
+               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;
+                       }
+               }
+       }
+}
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 39bae98425..21dabcfcea 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
@@ -50,6 +50,7 @@ package org.apache.royale.style.stylebeads.anim
 
                override public function set value(v:*):void
                {
+                       _value = v;
                        assert(
                                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"
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
index 82f91d2b33..25399dab0e 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionDuration.as
@@ -30,15 +30,53 @@ package org.apache.royale.style.stylebeads.anim
                        super("duration", "transition-duration", value);
                }
 
-               override public function set value(value:*):void
+               override public function set value(val:*):void
                {
-                       _value = value;
-                       assert(value == "default" || isVar(value) || 
(isInt(value) && value >= 0), "transition-duration only accepts valid CSS 
variables or non-negative integers representing milliseconds");
-                       calculatedSelector = value;
-                       if(value == "default")
+                       _value = val;
+                       if(val == "default")
+                       {
+                               calculatedSelector = val;
                                calculatedRuleValue = 
ThemeManager.instance.activeTheme.defaultTransitionDuration;
+                       }
+                       else if(isVar(val))
+                       {
+                               calculatedSelector = val;
+                               calculatedRuleValue = fromVar(val);
+                       }
+                       else if(isInt(val))
+                       {
+                               assert(val >= 0, "transition-duration only 
accepts non-negative integers representing milliseconds");
+                               calculatedSelector = val;
+                               calculatedRuleValue = val + "ms";
+                       }
+                       else if(val is String)
+                       {
+                               // Handle comma separated durations like 
'130ms, 130ms, 0s'
+                               var durations:Array = (val as 
String).split(",");
+                               var formattedDurations:Array = [];
+                               for (var i:int = 0; i < durations.length; i++)
+                               {
+                                       var duration:String = 
durations[i].trim();
+                                       // If it's a number, assume it's 
milliseconds and add the unit
+                                       if (isInt(duration))
+                                       {
+                                               
formattedDurations.push(duration + "ms");
+                                       }
+                                       else
+                                       {
+                                               // Assume it already has a unit 
(ms, s) or it's a variable
+                                               var resolved:String = 
acceptVar(duration);
+                                               assert(resolved, 
"transition-duration only accepts valid CSS variables, non-negative integers 
representing milliseconds, or a comma-separated sequence of durations");
+                                               
formattedDurations.push(resolved);
+                                       }
+                               }
+                               calculatedSelector = (val as 
String).replace(/,/g, "-").replace(/\s/g, "");
+                               calculatedRuleValue = 
formattedDurations.join(", ");
+                       }
                        else
-                               calculatedRuleValue = isInt(value) ? value + 
"ms" : fromVar(value);
+                       {
+                               assert(false, "transition-duration only accepts 
valid CSS variables, non-negative integers representing milliseconds, or a 
comma-separated sequence of durations");
+                       }
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionProperty.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionProperty.as
index 9d58922f81..a9fe584635 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionProperty.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionProperty.as
@@ -40,6 +40,12 @@ package org.apache.royale.style.stylebeads.anim
                override public function set value(value:*):void
                {
                        _value = value;
+                       /*if(value == null)
+                       {
+                               calculatedSelector = null;
+                               calculatedRuleValue = null;
+                               return;
+                       }*/
                        switch(value)
                        {
                                case "default":
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionTimingFunction.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionTimingFunction.as
index ee0f6057d2..96dc0ef1e6 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionTimingFunction.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/anim/TransitionTimingFunction.as
@@ -33,33 +33,61 @@ package org.apache.royale.style.stylebeads.anim
                override public function set value(value:*):void
                {
                        _value = value;
-                       var ruleValue:String = value;
-                       var selectorValue:String = value;
+                       if (value is String && (value as String).indexOf(",") 
!= -1)
+                       {
+                               var parts:Array = (value as String).split(",");
+                               var resolvedParts:Array = [];
+                               for (var i:int = 0; i < parts.length; i++)
+                               {
+                                       
resolvedParts.push(resolveTimingFunction(parts[i].trim()));
+                               }
+                               calculatedRuleValue = resolvedParts.join(", ");
+                               calculatedSelector = (value as 
String).replace(/,/g, "-").replace(/\s/g, "");
+                       }
+                       else
+                       {
+                               calculatedRuleValue = 
resolveTimingFunction(value);
+                               calculatedSelector = value;
+                       }
+               }
+
+               private function resolveTimingFunction(val:*):String
+               {
+                       var ruleValue:String = val;
                        var theme:StyleTheme = 
ThemeManager.instance.activeTheme;
-                       switch(value)
+                       switch(val)
                        {
                                case "default":
                                        ruleValue = 
theme.defaultTransitionTimingFunction;
                                        break;
+                               case "in-out":
+                               case "ease-in-out":
+                                       ruleValue = theme.easeInOut;
+                                       break;
                                case "in":
+                               case "ease-in":
                                        ruleValue = theme.easeIn;
                                        break;
                                case "out":
+                               case "ease-out":
                                        ruleValue = theme.easeOut;
                                        break;
-                               case "in-out":
-                                       ruleValue = theme.easeInOut;
+                               case "ease":
+                                       ruleValue = "ease";
                                        break;
                                case "linear":
                                case "initial":
                                        break;
                                default:
-                                       ruleValue = 
CSSLookup.getProperty(value);
+                                       ruleValue = acceptVar(val as String);
+                                       if (ruleValue == val)
+                                       {
+                                               ruleValue = 
CSSLookup.getProperty(val);
+                                       }
                                        break;
                        }
-                       assert(ruleValue, "transition-timing-function only 
accepts 'linear', 'in', 'out', 'in-out', 'initial', or a valid CSS timing 
function value");
-                       calculatedSelector = selectorValue;
-                       calculatedRuleValue = ruleValue;
+                       assert(ruleValue, "transition-timing-function only 
accepts 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'initial', or a 
valid CSS timing function value");
+                       return ruleValue;
                }
        }
 }
\ No newline at end of file
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/transform/Transform.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/transform/Transform.as
index 7c1b7fa523..aa65ac51e9 100644
--- 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/transform/Transform.as
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/stylebeads/transform/Transform.as
@@ -29,6 +29,12 @@ package org.apache.royale.style.stylebeads.transform
                }
                override public function set value(value:*):void
                {
+                       if(value == null)
+                       {
+                               _value = null;
+                               calculateValue();
+                               return;
+                       }
                        assert(isVar(value) || value == "none", "Invalid value 
for transform: " + value);
                        calculatedSelector = calculatedRuleValue = _value = 
value;
                        if(isVar(value))
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
index ea9100260b..bbc5363405 100644
--- 
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
@@ -88,5 +88,17 @@ package org.apache.royale.style.support
                }
                
                
+               /**
+                * @royalesuppressexport
+                */
+               public static function help_medium():Icon{
+                       if (!Icon.isRegistered('support_icons_help_medium')) {
+                               Icon.registerIcon('support_icons_help_medium', 
<svg viewBox="0 0 20 20" fill="currentColor" stroke="none"><path d="M11 3a8 8 0 
1 0 8 8a8 8 0 0 0-8-8zm1.3 12.3a1.222 1.222 0 0 1-.3.9a1.223 1.223 0 0 
1-.9.3a1.2 1.2 0 0 1 0-2.4c.8 0 1.3.5 1.2 1.2zm.1-4.5c-.4.4-.8.8-.8 1.2a1.135 
1.135 0 0 0 .3.8v.1a.098.098 0 0 1-.096.1H10.4a.229.229 0 0 1-.2-.1a1.666 1.666 
0 0 1-.4-1.1a2.772 2.772 0 0 1 1-1.7a2.772 2.772 0 0 0 
1-1.7c0-.5-.4-1.1-1.4-1.1a5.018 5.018 0 0 0-2 .4h-.2V6.3c0-.1 0-.2.1-.2a6.183 
[...]
+                       }
+                       return new Icon('support_icons_help_medium');
+               }
+               
+               
+               
        }
 }


Reply via email to