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

yishayw 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 e11c6904d3 Added tabs
     new 96cf785c9c Merge branch 'develop' of 
https://github.com/apache/royale-asjs into develop
e11c6904d3 is described below

commit e11c6904d34dd54e99d8523da75913c07e96dd16
Author: Yishay Weiss <[email protected]>
AuthorDate: Tue Apr 14 15:22:28 2026 +0300

    Added tabs
---
 .../projects/Style/src/main/resources/defaults.css |   8 ++
 .../Style/src/main/resources/style-manifest.xml    |   4 +
 .../src/main/royale/org/apache/royale/style/Tab.as | 153 +++++++++++++++++++++
 .../main/royale/org/apache/royale/style/TabBar.as  | 140 +++++++++++++++++++
 .../org/apache/royale/style/skins/ITabSkin.as      |  27 ++++
 .../org/apache/royale/style/skins/TabBarSkin.as    |  76 ++++++++++
 .../org/apache/royale/style/skins/TabSkin.as       | 151 ++++++++++++++++++++
 7 files changed, 559 insertions(+)

diff --git a/frameworks/projects/Style/src/main/resources/defaults.css 
b/frameworks/projects/Style/src/main/resources/defaults.css
index f4f028200b..77162e985b 100644
--- a/frameworks/projects/Style/src/main/resources/defaults.css
+++ b/frameworks/projects/Style/src/main/resources/defaults.css
@@ -59,6 +59,14 @@ Dropdown
 {
        IStyleSkin: 
ClassReference("org.apache.royale.style.skins.DropdownSkin");
 }
+Tab
+{
+       IStyleSkin: ClassReference("org.apache.royale.style.skins.TabSkin");
+}
+TabBar
+{
+       IStyleSkin: ClassReference("org.apache.royale.style.skins.TabBarSkin");
+}
 Toggle
 {
        IStyleSkin: ClassReference("org.apache.royale.style.skins.ToggleSkin");
diff --git a/frameworks/projects/Style/src/main/resources/style-manifest.xml 
b/frameworks/projects/Style/src/main/resources/style-manifest.xml
index 0bc6f3cc71..36ad8784ad 100644
--- a/frameworks/projects/Style/src/main/resources/style-manifest.xml
+++ b/frameworks/projects/Style/src/main/resources/style-manifest.xml
@@ -30,6 +30,8 @@
   <component id="CheckBox" class="org.apache.royale.style.CheckBox"/>
   <component id="Divider" class="org.apache.royale.style.Divider"/>
   <component id="Dropdown" class="org.apache.royale.style.Dropdown"/>
+  <component id="Tab" class="org.apache.royale.style.Tab"/>
+  <component id="TabBar" class="org.apache.royale.style.TabBar"/>
   <component id="Toggle" class="org.apache.royale.style.Toggle"/>
   <component id="FlexContainer" class="org.apache.royale.style.FlexContainer"/>
   <component id="GridContainer" class="org.apache.royale.style.GridContainer"/>
@@ -326,6 +328,8 @@
   <component id="AccordionSectionSkin" 
class="org.apache.royale.style.skins.AccordionSectionSkin"/>
   <component id="AccordionContentSkin" 
class="org.apache.royale.style.skins.AccordionContentSkin"/>
   <component id="ListRendererSkin" 
class="org.apache.royale.style.skins.ListRendererSkin"/>
+  <component id="TabSkin" class="org.apache.royale.style.skins.TabSkin"/>
+  <component id="TabBarSkin" class="org.apache.royale.style.skins.TabBarSkin"/>
   <component id="ToggleSkin" class="org.apache.royale.style.skins.ToggleSkin"/>
 
 </componentPackage>
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Tab.as 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Tab.as
new file mode 100644
index 0000000000..530e741a27
--- /dev/null
+++ b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Tab.as
@@ -0,0 +1,153 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+       COMPILE::JS{
+               import org.apache.royale.core.WrappedHTMLElement;
+       }
+       import org.apache.royale.events.Event;
+       import org.apache.royale.style.elements.Span;
+       import org.apache.royale.style.skins.ITabSkin;
+
+       /**
+        *  Dispatched when the user clicks on the tab.
+        */
+       [Event(name="itemClicked", type="org.apache.royale.events.Event")]
+
+       public class Tab extends StyleUIBase
+       {
+
+               public function Tab()
+               {
+                       super();
+               }
+
+               private var labelSpan:Span;
+
+               override protected function getTag():String
+               {
+                       return "button";
+               }
+
+               COMPILE::JS
+               override protected function createElement():WrappedHTMLElement
+               {
+                       var elem:WrappedHTMLElement = super.createElement();
+                       elem.setAttribute("role", "tab");
+                       elem.setAttribute("type", "button");
+                       elem.onclick = elementClicked;
+
+                       return elem;
+               }
+
+               COMPILE::JS
+               private function elementClicked():void
+               {
+                       dispatchEvent(new Event("itemClicked"));
+               }
+
+               private var _text:String = "";
+
+               public function get text():String
+               {
+                       return _text;
+               }
+
+               public function set text(value:String):void
+               {
+                       if(_text != value)
+                       {
+                               _text = value;
+                               if(!labelSpan)
+                               {
+                                       labelSpan = new Span();
+                                       addElement(labelSpan);
+                                       if(_stylesLoaded)
+                                       {
+                                               applyLabelSkin();
+                                       }
+                               }
+                               labelSpan.text = value;
+                       }
+               }
+
+               private var _selected:Boolean;
+
+               public function get selected():Boolean
+               {
+                       return _selected;
+               }
+
+               public function set selected(value:Boolean):void
+               {
+                       if(value != _selected)
+                       {
+                               _selected = value;
+                               toggleAttribute("data-selected", value);
+                               COMPILE::JS
+                               {
+                                       element.setAttribute("aria-selected", 
value ? "true" : "false");
+                               }
+                       }
+               }
+
+               private var _disabled:Boolean;
+
+               public function get disabled():Boolean
+               {
+                       return _disabled;
+               }
+
+               public function set disabled(value:Boolean):void
+               {
+                       if(value != _disabled)
+                       {
+                               _disabled = value;
+                               toggleAttribute("data-disabled", value);
+                               COMPILE::JS
+                               {
+                                       (element as HTMLButtonElement).disabled 
= value;
+                               }
+                       }
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.skins.ITabSkin
+                */
+               override protected function applySkin():void
+               {
+                       applyLabelSkin();
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.skins.ITabSkin
+                */
+               private function applyLabelSkin():void
+               {
+                       if(!labelSpan) return;
+                       var tabSkin:ITabSkin = skin as ITabSkin;
+                       labelSpan.setStyles(tabSkin.labelStyles, true);
+               }
+
+               override public function getWrapperStyle():String
+               {
+                       return 'tab';
+               }
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/TabBar.as 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/TabBar.as
new file mode 100644
index 0000000000..1d9c60d3fa
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/TabBar.as
@@ -0,0 +1,140 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+       COMPILE::JS{
+               import org.apache.royale.core.WrappedHTMLElement;
+       }
+       import org.apache.royale.events.Event;
+       import org.apache.royale.events.ValueChangeEvent;
+
+       /**
+        *  Dispatched when the selected tab changes.
+        */
+       [Event(name="change", type="org.apache.royale.events.Event")]
+
+       [DefaultProperty("tabs")]
+
+       public class TabBar extends StyleUIBase
+       {
+
+               public function TabBar()
+               {
+                       super();
+               }
+
+               COMPILE::JS
+               override protected function createElement():WrappedHTMLElement
+               {
+                       var elem:WrappedHTMLElement = super.createElement();
+                       elem.setAttribute("role", "tablist");
+                       return elem;
+               }
+
+               public function get tabs():Array
+               {
+                       var result:Array = [];
+                       for(var i:int = 0; i < numElements; i++)
+                               result.push(getElementAt(i));
+                       return result;
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Tab
+                */
+               public function set tabs(value:Array):void
+               {
+                       while(numElements > 0)
+                       {
+                               var oldTab:Tab = getElementAt(0) as Tab;
+                               oldTab.removeEventListener("itemClicked", 
itemClickedHandler);
+                               removeElement(oldTab);
+                       }
+                       if(value)
+                       {
+                               for each(var tab:Tab in value)
+                               {
+                                       tab.addEventListener("itemClicked", 
itemClickedHandler);
+                                       addElement(tab);
+                               }
+                               if(_selectedIndex >= 0 && _selectedIndex < 
value.length)
+                                       value[_selectedIndex].selected = true;
+                       }
+               }
+
+               private var _selectedIndex:int = -1;
+
+               
[Bindable(event='valueChange',type='org.apache.royale.events.ValueChangeEvent')]
+               public function get selectedIndex():int
+               {
+                       return _selectedIndex;
+               }
+
+               public function set selectedIndex(value:int):void
+               {
+                       if(value != _selectedIndex)
+                       {
+                               var oldValue:int = _selectedIndex;
+                               selectTab(value);
+                               
dispatchEvent(ValueChangeEvent.createUpdateEvent(this, 'selectedIndex', 
oldValue, value));
+                               dispatchEvent(new Event("change"));
+                       }
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Tab
+                */
+               public function get selectedTab():Tab
+               {
+                       if(_selectedIndex >= 0 && _selectedIndex < numElements)
+                               return getElementAt(_selectedIndex) as Tab;
+                       return null;
+               }
+
+               private function itemClickedHandler(event:Event):void
+               {
+                       var tab:Tab = event.target as Tab;
+                       for(var i:int = 0; i < numElements; i++)
+                       {
+                               if(getElementAt(i) == tab)
+                               {
+                                       selectedIndex = i;
+                                       return;
+                               }
+                       }
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Tab
+                */
+               private function selectTab(index:int):void
+               {
+                       for(var i:int = 0; i < numElements; i++)
+                       {
+                               (getElementAt(i) as Tab).selected = (i == 
index);
+                       }
+                       _selectedIndex = index;
+               }
+
+               override public function getWrapperStyle():String
+               {
+                       return 'tab-bar';
+               }
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ITabSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ITabSkin.as
new file mode 100644
index 0000000000..39f549af80
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ITabSkin.as
@@ -0,0 +1,27 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.IStyleSkin;
+
+       public interface ITabSkin extends IStyleSkin
+       {
+               function get labelStyles():Array;
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TabBarSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TabBarSkin.as
new file mode 100644
index 0000000000..9ffea098bc
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TabBarSkin.as
@@ -0,0 +1,76 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.TabBar;
+       import org.apache.royale.core.IStrand;
+       import org.apache.royale.style.colors.ColorSwatch;
+       import org.apache.royale.style.colors.ThemeColorSet;
+       import org.apache.royale.style.util.ThemeManager;
+       import org.apache.royale.style.stylebeads.layout.Display;
+       import org.apache.royale.style.stylebeads.flexgrid.AlignItems;
+       import org.apache.royale.style.stylebeads.flexgrid.FlexWrap;
+       import org.apache.royale.style.stylebeads.border.Border;
+       import org.apache.royale.style.stylebeads.border.BorderWidth;
+
+       public class TabBarSkin extends StyleSkin
+       {
+               public function TabBarSkin()
+               {
+                       super();
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.TabBar
+                */
+               private function get host():TabBar
+               {
+                       return _strand as TabBar;
+               }
+
+               override public function set strand(value:IStrand):void
+               {
+                       super.strand = value;
+                       applyStyles();
+               }
+
+               private function applyStyles():void
+               {
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
+                       var borderColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 200);
+
+                       var border:Border = new Border();
+                       border.bottomColor = borderColor.colorSpecifier;
+                       border.bottomStyle = "solid";
+
+                       var borderWidth:BorderWidth = new BorderWidth();
+                       borderWidth.bottom = 1;
+
+                       _styles = [
+                               new Display("flex"),
+                               new AlignItems("end"),
+                               new FlexWrap("wrap"),
+                               borderWidth,
+                               border
+                       ];
+                       host.setStyles(_styles);
+               }
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TabSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TabSkin.as
new file mode 100644
index 0000000000..03a3a04639
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/TabSkin.as
@@ -0,0 +1,151 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.Tab;
+       import org.apache.royale.core.IStrand;
+       import org.apache.royale.style.colors.ColorSwatch;
+       import org.apache.royale.style.colors.ThemeColorSet;
+       import org.apache.royale.style.util.ThemeManager;
+       import org.apache.royale.style.stylebeads.interact.Cursor;
+       import org.apache.royale.style.stylebeads.interact.UserSelect;
+       import org.apache.royale.style.stylebeads.background.BackgroundColor;
+       import org.apache.royale.style.stylebeads.border.Border;
+       import org.apache.royale.style.stylebeads.border.BorderWidth;
+       import org.apache.royale.style.stylebeads.border.Outline;
+       import org.apache.royale.style.stylebeads.spacing.Padding;
+       import org.apache.royale.style.stylebeads.anim.Transition;
+       import org.apache.royale.style.stylebeads.typography.FontSize;
+       import org.apache.royale.style.stylebeads.typography.TextColor;
+       import org.apache.royale.style.stylebeads.states.attribute.DataState;
+       import org.apache.royale.style.stylebeads.states.FocusVisibleState;
+
+       public class TabSkin extends StyleSkin implements ITabSkin
+       {
+               public function TabSkin()
+               {
+                       super();
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Tab
+                */
+               private function get host():Tab
+               {
+                       return _strand as Tab;
+               }
+
+               override public function set strand(value:IStrand):void
+               {
+                       super.strand = value;
+                       applyStyles();
+               }
+
+               private function applyStyles():void
+               {
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
+                       var primaryColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.PRIMARY, 500);
+                       var disabledColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 300, 50);
+
+                       var size:Number = 16 * getMultiplier();
+                       var paddingH:String = computeSize(size * 0.75, 
host.unit);
+                       var paddingV:String = computeSize(size * 0.5, 
host.unit);
+
+                       var outline:Outline = new Outline();
+                       outline.unit = host.unit;
+                       outline.width = 0.5;
+                       outline.style = "solid";
+                       outline.color = primaryColor.getVariant(NaN, 
40).colorSpecifier;
+                       outline.offset = 0.5;
+
+                       var padding:Padding = new Padding();
+                       padding.left = paddingH;
+                       padding.right = paddingH;
+                       padding.top = paddingV;
+                       padding.bottom = paddingV;
+
+                       var borderWidth:BorderWidth = new BorderWidth();
+                       borderWidth.bottom = 2;
+
+                       var defaultBorder:Border = new Border();
+                       defaultBorder.bottomColor = "transparent";
+                       defaultBorder.bottomStyle = "solid";
+
+                       var selectedBorder:Border = new Border();
+                       selectedBorder.bottomColor = 
primaryColor.colorSpecifier;
+
+                       _styles = [
+                               new BackgroundColor("transparent"),
+                               padding,
+                               borderWidth,
+                               defaultBorder,
+                               new Cursor("pointer"),
+                               new UserSelect("none"),
+                               new Transition(),
+                               new DataState("selected", [
+                                       selectedBorder,
+                                       new TextColor(primaryColor)
+                               ]),
+                               new DataState("disabled", [
+                                       new TextColor(disabledColor),
+                                       new Cursor("default")
+                               ]),
+                               new FocusVisibleState([outline])
+                       ];
+                       host.setStyles(_styles);
+               }
+
+               private function getMultiplier():Number
+               {
+                       switch(host.size)
+                       {
+                               case "sm":
+                                       return 0.875;
+                               case "md":
+                                       return 1;
+                               case "lg":
+                                       return 1.125;
+                               case "xl":
+                                       return 1.25;
+                               default:
+                                       return 1;
+                       }
+               }
+
+               private var _labelStyles:Array;
+
+               public function get labelStyles():Array
+               {
+                       if(!_labelStyles)
+                               createLabelStyles();
+                       return _labelStyles;
+               }
+
+               private function createLabelStyles():void
+               {
+                       var size:Number = 16 * getMultiplier();
+                       var fontSize:String = computeSize(size, host.unit);
+
+                       _labelStyles = [
+                               new FontSize(fontSize)
+                       ];
+               }
+       }
+}

Reply via email to