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 ca7254fe79 Added Toggle
ca7254fe79 is described below

commit ca7254fe79fe72498788c54683b111de819d15ee
Author: Yishay Weiss <[email protected]>
AuthorDate: Tue Apr 14 11:24:25 2026 +0300

    Added Toggle
---
 .../projects/Style/src/main/resources/defaults.css |   4 +
 .../Style/src/main/resources/style-manifest.xml    |   2 +
 .../main/royale/org/apache/royale/style/Toggle.as  | 182 +++++++++++++++
 .../org/apache/royale/style/skins/IToggleSkin.as   |  29 +++
 .../org/apache/royale/style/skins/ToggleSkin.as    | 243 +++++++++++++++++++++
 5 files changed, 460 insertions(+)

diff --git a/frameworks/projects/Style/src/main/resources/defaults.css 
b/frameworks/projects/Style/src/main/resources/defaults.css
index 8144ff87b2..f4f028200b 100644
--- a/frameworks/projects/Style/src/main/resources/defaults.css
+++ b/frameworks/projects/Style/src/main/resources/defaults.css
@@ -59,6 +59,10 @@ Dropdown
 {
        IStyleSkin: 
ClassReference("org.apache.royale.style.skins.DropdownSkin");
 }
+Toggle
+{
+       IStyleSkin: ClassReference("org.apache.royale.style.skins.ToggleSkin");
+}
 
 DataItemRenderer
 {
diff --git a/frameworks/projects/Style/src/main/resources/style-manifest.xml 
b/frameworks/projects/Style/src/main/resources/style-manifest.xml
index f96c9ea7ef..0bc6f3cc71 100644
--- a/frameworks/projects/Style/src/main/resources/style-manifest.xml
+++ b/frameworks/projects/Style/src/main/resources/style-manifest.xml
@@ -30,6 +30,7 @@
   <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="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"/>
   <component id="StyleSkin" class="org.apache.royale.style.StyleSkin"/>
@@ -325,5 +326,6 @@
   <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="ToggleSkin" class="org.apache.royale.style.skins.ToggleSkin"/>
 
 </componentPackage>
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Toggle.as 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Toggle.as
new file mode 100644
index 0000000000..ce89a8646a
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/Toggle.as
@@ -0,0 +1,182 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.ValueChangeEvent;
+       import org.apache.royale.core.IHasLabel;
+       import org.apache.royale.style.elements.Div;
+       import org.apache.royale.style.elements.Span;
+       import org.apache.royale.style.skins.IToggleSkin;
+       import org.apache.royale.style.stylebeads.utils.ScreenReader;
+
+       /**
+        *  Dispatched when the user toggles the switch.
+        */
+       [Event(name="change", type="org.apache.royale.events.Event")]
+
+       public class Toggle extends StyleUIBase implements IHasLabel
+       {
+
+               public function Toggle()
+               {
+                       super();
+               }
+
+               COMPILE::JS
+               private var input:HTMLInputElement;
+
+               private var track:Div;
+
+               private var thumb:Div;
+
+               COMPILE::JS
+               private function elementClicked():void
+               {
+                       processCheckedChange(input.checked, false);
+               }
+
+               override protected function getTag():String
+               {
+                       return "label";
+               }
+
+               COMPILE::JS
+               override protected function createElement():WrappedHTMLElement
+               {
+                       var elem:WrappedHTMLElement = super.createElement();
+                       input = newElement("input") as HTMLInputElement;
+                       input.type = "checkbox";
+                       var srOnly:String = new ScreenReader().getSelector();
+                       input.className = ("peer " + srOnly);
+                       input.onclick = elementClicked;
+                       elem.appendChild(input);
+
+                       track = new Div();
+                       addElement(track);
+
+                       thumb = new Div();
+                       track.addElement(thumb);
+
+                       return elem;
+               }
+
+               private var _label:String = "";
+
+               public function get label():String
+               {
+                       return _label;
+               }
+
+               private var span:Span;
+
+               public function set label(value:String):void
+               {
+                       COMPILE::JS
+                       {
+                               if(_label != value){
+                                       _label = value;
+                                       if(!span){
+                                               span = new Span();
+                                               addElement(span);
+                                               if(_stylesLoaded)
+                                               {
+                                                       applyLabelSkin();
+                                               }
+                                       }
+                                       span.text = value;
+                                       input.setAttribute("aria-label", value);
+                               }
+                       }
+               }
+
+               /**
+                * @royaleignorecoercion 
org.apache.royale.style.skins.IToggleSkin
+                */
+               override protected function applySkin():void
+               {
+                       var toggleSkin:IToggleSkin = skin as IToggleSkin;
+                       track.setStyles(toggleSkin.trackStyles, true);
+                       thumb.setStyles(toggleSkin.thumbStyles, true);
+                       applyLabelSkin();
+               }
+
+               /**
+                * @royaleignorecoercion 
org.apache.royale.style.skins.IToggleSkin
+                */
+               private function applyLabelSkin():void
+               {
+                       if(!span) return;
+                       var toggleSkin:IToggleSkin = skin as IToggleSkin;
+                       span.setStyles(toggleSkin.labelStyles, true);
+               }
+
+               private var _disabled:Boolean;
+
+               public function get disabled():Boolean
+               {
+                       return _disabled;
+               }
+
+               public function set disabled(value:Boolean):void
+               {
+                       COMPILE::JS
+                       {
+                               if(value != _disabled){
+                                       input.disabled = value;
+                                       toggleAttribute("data-disabled", value);
+                               }
+                       }
+                       _disabled = value;
+               }
+
+               private var _checked:Boolean;
+
+               
[Bindable(event='valueChange',type='org.apache.royale.events.ValueChangeEvent')]
+               public function get checked():Boolean
+               {
+                       return _checked;
+               }
+
+               public function set checked(value:Boolean):void
+               {
+                       processCheckedChange(value, true);
+               }
+
+               private function processCheckedChange(value:Boolean, 
programmatic:Boolean):void
+               {
+                       COMPILE::JS
+                       {
+                               if(value != _checked){
+                                       _checked = value;
+                                       if (programmatic) input.checked = value;
+                                       toggleAttribute("data-checked", value);
+                                       
dispatchEvent(ValueChangeEvent.createUpdateEvent(this, 'checked', !value, 
value));
+                               }
+                       }
+               }
+
+               override public function getWrapperStyle():String
+               {
+                       return 'toggle';
+               }
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/IToggleSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/IToggleSkin.as
new file mode 100644
index 0000000000..39722e43d3
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/IToggleSkin.as
@@ -0,0 +1,29 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 IToggleSkin extends IStyleSkin
+       {
+               function get trackStyles():Array;
+               function get thumbStyles():Array;
+               function get labelStyles():Array;
+       }
+}
diff --git 
a/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ToggleSkin.as
 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ToggleSkin.as
new file mode 100644
index 0000000000..8ec655e6c5
--- /dev/null
+++ 
b/frameworks/projects/Style/src/main/royale/org/apache/royale/style/skins/ToggleSkin.as
@@ -0,0 +1,243 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.Toggle;
+       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.layout.Position;
+       import org.apache.royale.style.stylebeads.layout.Left;
+       import org.apache.royale.style.stylebeads.layout.Top;
+       import org.apache.royale.style.stylebeads.interact.Cursor;
+       import org.apache.royale.style.stylebeads.interact.UserSelect;
+       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.border.Outline;
+       import org.apache.royale.style.stylebeads.background.BackgroundColor;
+       import org.apache.royale.style.stylebeads.anim.Transition;
+       import org.apache.royale.style.stylebeads.transform.Transform;
+       import org.apache.royale.style.stylebeads.typography.FontSize;
+       import org.apache.royale.style.stylebeads.typography.TextColor;
+       import org.apache.royale.style.stylebeads.states.PeerPseudo;
+       import org.apache.royale.style.stylebeads.states.GroupPseudo;
+       import org.apache.royale.style.stylebeads.states.CheckedState;
+       import org.apache.royale.style.stylebeads.states.DisabledState;
+       import org.apache.royale.style.stylebeads.states.FocusVisibleState;
+       import org.apache.royale.style.stylebeads.states.attribute.DataState;
+       import org.apache.royale.style.stylebeads.flexgrid.AlignItems;
+       import org.apache.royale.style.stylebeads.flexgrid.ColumnGap;
+
+       public class ToggleSkin extends StyleSkin implements IToggleSkin
+       {
+               public function ToggleSkin()
+               {
+                       super();
+               }
+
+               /**
+                * @royaleignorecoercion org.apache.royale.style.Toggle
+                */
+               private function get host():Toggle
+               {
+                       return _strand as Toggle;
+               }
+
+               override public function set strand(value:IStrand):void
+               {
+                       super.strand = value;
+                       applyStyles();
+               }
+
+               private function applyStyles():void
+               {
+                       var size:Number = 16 * getMultiplier();
+                       var gap:String = computeSize(size * 0.5, host.unit);
+
+                       _styles = [
+                               new Display("inline-flex"),
+                               new AlignItems("center"),
+                               new ColumnGap(gap),
+                               new UserSelect("none"),
+                               new Cursor("pointer"),
+                               new DataState("disabled", [
+                                       new Cursor("default")
+                               ])
+                       ];
+                       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 _trackStyles:Array;
+
+               public function get trackStyles():Array
+               {
+                       if(!_trackStyles)
+                               createTrackStyles();
+                       return _trackStyles;
+               }
+
+               public function set trackStyles(value:Array):void
+               {
+                       _trackStyles = value;
+               }
+
+               private function createTrackStyles():void
+               {
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
+                       var primaryColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.PRIMARY, 500);
+                       var uncheckedColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.NEUTRAL, 300);
+                       var disabledColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 200, 50);
+
+                       var size:Number = 16 * getMultiplier();
+                       var trackHeight:String = computeSize(size * 1.5, 
host.unit);
+                       var trackWidth:String = computeSize(size * 2.75, 
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;
+
+                       _trackStyles = [
+                               new Position("relative"),
+                               new HeightStyle(trackHeight),
+                               new WidthStyle(trackWidth),
+                               new BorderRadius("9999px"),
+                               new BackgroundColor(uncheckedColor),
+                               new Transition(),
+                               new PeerPseudo([
+                                       new FocusVisibleState([outline]),
+                                       new CheckedState([
+                                               new 
BackgroundColor(primaryColor)
+                                       ]),
+                                       new DisabledState([
+                                               new 
BackgroundColor(disabledColor)
+                                       ])
+                               ])
+                       ];
+               }
+
+               private var _thumbStyles:Array;
+
+               public function get thumbStyles():Array
+               {
+                       if(!_thumbStyles)
+                               createThumbStyles();
+                       return _thumbStyles;
+               }
+
+               public function set thumbStyles(value:Array):void
+               {
+                       _thumbStyles = value;
+               }
+
+               private function createThumbStyles():void
+               {
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
+                       var thumbColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 0);
+                       var disabledThumbColor:ColorSwatch = 
colorSet.getSwatch(ThemeColorSet.BASE, 100, 50);
+
+                       var size:Number = 16 * getMultiplier();
+                       var thumbSize:String = computeSize(size * 1.25, 
host.unit);
+                       var inset:String = computeSize(size * 0.125, host.unit);
+                       var slideDistance:String = computeSize(size * 1.25, 
host.unit);
+
+                       var left:Left = new Left();
+                       left.value = inset;
+
+                       var top:Top = new Top();
+                       top.value = inset;
+
+                       var checkedTransform:Transform = new Transform();
+                       checkedTransform.translateX = slideDistance;
+
+                       _thumbStyles = [
+                               new Position("absolute"),
+                               left,
+                               top,
+                               new HeightStyle(thumbSize),
+                               new WidthStyle(thumbSize),
+                               new BorderRadius("9999px"),
+                               new BackgroundColor(thumbColor),
+                               new Transition(),
+                               new GroupPseudo([
+                                       new DataState("checked", 
[checkedTransform]),
+                                       new DataState("disabled", [
+                                               new 
BackgroundColor(disabledThumbColor)
+                                       ])
+                               ], host.getWrapperStyle())
+                       ];
+               }
+
+               private var _labelStyles:Array;
+
+               public function get labelStyles():Array
+               {
+                       if(!_labelStyles)
+                               createLabelStyles();
+                       return _labelStyles;
+               }
+
+               public function set labelStyles(value:Array):void
+               {
+                       _labelStyles = value;
+               }
+
+               private function createLabelStyles():void
+               {
+                       var size:Number = 16 * getMultiplier();
+                       var fontSize:String = computeSize(size, host.unit);
+                       var colorSet:ThemeColorSet = 
ThemeManager.instance.activeTheme.themeColorSet;
+                       var enabledColor:ColorSwatch = colorSet.baseContent;
+                       var disabledColor:ColorSwatch = 
colorSet.baseContentWeak;
+
+                       _labelStyles = [
+                               new FontSize(fontSize),
+                               new TextColor(enabledColor),
+                               new PeerPseudo([
+                                       new DisabledState([
+                                               new TextColor(disabledColor)
+                                       ])
+                               ])
+                       ];
+               }
+       }
+}

Reply via email to