Repository: microsoft/Teams-AdaptiveCards-Mobile
Pull request #356: Split button UI changes
Author: login: P-Harika
Created: 2025-04-24T11:45:52Z | Merged: 2025-04-30T08:17:43Z

Since ACRButton regression revert has been merged, raising this PR to include split button chevron down icon changes:

![image](https://github.com/user-attachments/assets/6678ea4b-41f7-437b-b8ca-9fc3f18be682)
![image](https://github.com/user-attachments/assets/7dc0c363-2416-4562-a7b1-12fd235df5c6)
![image](https://github.com/user-attachments/assets/733de69f-70c7-47db-af5d-4d858ea52287)



Diff:
diff --git a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.h b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.h
index 568cf550d..16c6cc739 100644
--- a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.h
+++ b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.h
@@ -17,6 +17,7 @@
 @property NSString *sentiment;
 @property (nonatomic, copy) NSString *tooltip;
 @property (nonatomic, readonly) NSString *inlineTooltip;
+@property (readonly) BOOL shouldFlipInRtl;
 
 - (NSString *)title;
 - (NSString *)elementId;
diff --git a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.mm b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.mm
index e105e3eee..e2163516e 100644
--- a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.mm
+++ b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.mm
@@ -152,6 +152,14 @@ - (BOOL)isEnabled
     return YES;
 }
 
+- (BOOL)shouldFlipInRtl
+{
+    if (_elem) {
+        return _elem->GetIsRtl();
+    }
+    return NO;
+}
+
 - (NSArray *)menuActions
 {
     NSMutableArray *menuActions = [NSMutableArray array];
diff --git a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOEnums.h b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOEnums.h
index 6f1e9b3e5..680f95780 100644
--- a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOEnums.h
+++ b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOEnums.h
@@ -21,6 +21,7 @@ typedef NS_ENUM(NSInteger, ACRActionType) {
 typedef NS_ENUM(NSInteger, ACRIconPlacement) {
     ACRAboveTitle = 0,
     ACRLeftOfTitle,
+    ACRRightOfTitle,
     ACRNoTitle,
 };
 
diff --git a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.h b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.h
index 61c14144a..91263db17 100644
--- a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.h
+++ b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.h
@@ -22,6 +22,7 @@
 @property ACRIconPlacement iconPlacement;
 @property ACRActionType actionType;
 @property __weak UIImageView *iconView;
+@property __weak UIImageView *trailingIconView;
 @property NSLayoutConstraint *heightConstraint;
 @property NSLayoutConstraint *titleWidthConstraint;
 
diff --git a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
index 6109be3a8..09aa35fc1 100644
--- a/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
+++ b/source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
@@ -100,14 +100,22 @@ - (void)setupDefaultConfig
 - (void)setImageView:(UIImage *)image
           withConfig:(ACOHostConfig *)config
 {
-    [self setImageView:image withConfig:config widthToHeightRatio:0.0f];
+    [self setImageView:image withConfig:config aspectRatio:0.0f];
 }
 
 - (void)setImageView:(UIImage *)image
           withConfig:(ACOHostConfig *)config
-  widthToHeightRatio:(float)widthToHeightRatio
+  aspectRatio:(float)aspectRatio
 {
-    float imageHeight = 0.0f;
+    [self setImageView:image withConfig:config aspectRatio:aspectRatio imageSize:CGSizeZero];
+}
+
+- (void)setImageView:(UIImage *)image
+          withConfig:(ACOHostConfig *)config
+  aspectRatio:(float)aspectRatio
+           imageSize:(CGSize)imageSize
+{
+    CGFloat imageHeight = 0.0f;
     CGSize contentSize = [self.titleLabel intrinsicContentSize];
     
     // apply explicit image size when the below condition is met
@@ -118,10 +126,10 @@ - (void)setImageView:(UIImage *)image
     }
     
     if (image && image.size.height > 0) {
-        widthToHeightRatio = image.size.width / image.size.height;
+        aspectRatio = image.size.width / image.size.height;
     }
     
-    CGSize imageSize = CGSizeMake(imageHeight * widthToHeightRatio, imageHeight);
+    CGSize calculatedImageSize = CGSizeEqualToSize(imageSize, CGSizeZero) ? CGSizeMake(imageHeight * aspectRatio, imageHeight) : imageSize;
     _iconView.translatesAutoresizingMaskIntoConstraints = NO;
     
     // scale the image using UIImageView
@@ -131,7 +139,7 @@ - (void)setImageView:(UIImage *)image
                                     toItem:nil
                                  attribute:NSLayoutAttributeNotAnAttribute
                                 multiplier:1.0
-                                  constant:imageSize.width]
+                                  constant:calculatedImageSize.width]
         .active = YES;
     
     [NSLayoutConstraint constraintWithItem:_iconView
@@ -140,7 +148,7 @@ - (void)setImageView:(UIImage *)image
                                     toItem:nil
                                  attribute:NSLayoutAttributeNotAnAttribute
                                 multiplier:1.0
-                                  constant:imageSize.height]
+                                  constant:calculatedImageSize.height]
         .active = YES;
     
     int iconPadding = [config getHostConfig]->GetSpacing().defaultSpacing;
@@ -166,15 +174,15 @@ - (void)setImageView:(UIImage *)image
         // image can't be postion at the top of the title, so adjust title inset edges
         [self setTitleEdgeInsets:UIEdgeInsetsMake(0, iconPadding, -imageHeight - iconPadding, 0)];
         [self setImageEdgeInsets:UIEdgeInsetsMake(0, 0, -imageHeight - iconPadding, 0)];
-        CGFloat insetConstant = (imageSize.height + iconPadding) / 2;
+        CGFloat insetConstant = (calculatedImageSize.height + iconPadding) / 2;
         [self setContentEdgeInsets:UIEdgeInsetsMake(self.contentEdgeInsets.top + insetConstant, 0, self.contentEdgeInsets.bottom + insetConstant, 0)];
-    } else if (_iconPlacement != ACRNoTitle) {
+    } else if (_iconPlacement == ACRLeftOfTitle) {
         int npadding = 0;
         if (self.doesItHaveAnImageView) {
             iconPadding += (self.imageView.frame.size.width + iconPadding);
             npadding = [config getHostConfig]->GetSpacing().defaultSpacing;
         }
-        CGFloat widthOffset = (imageSize.width + iconPadding);
+        CGFloat widthOffset = (calculatedImageSize.width + iconPadding);
         
         [self setContentEdgeInsets:UIEdgeInsetsMake(self.contentEdgeInsets.top, self.contentEdgeInsets.left + widthOffset / 2, self.contentEdgeInsets.bottom, self.contentEdgeInsets.right + widthOffset / 2)];
         [self setTitleEdgeInsets:UIEdgeInsetsMake(0, npadding, 0, -(widthOffset + npadding))];
@@ -188,6 +196,48 @@ - (void)setImageView:(UIImage *)image
         
         [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:(widthOffset / 2)].active = YES;
         
+        self.heightConstraint = [self.heightAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.heightAnchor constant:self.contentEdgeInsets.top + self.contentEdgeInsets.bottom];
+        self.heightConstraint.active = YES;
+    } else if (_iconPlacement == ACRRightOfTitle) {
+        int npadding = 0;
+        if (self.doesItHaveAnImageView) {
+            iconPadding += (self.imageView.frame.size.width + iconPadding);
+            npadding = [config getHostConfig]->GetSpacing().defaultSpacing;
+        }
+
+        CGFloat widthOffset = (calculatedImageSize.width + iconPadding);
+
+        // Adjust content insets to accommodate icon on the right
+        [self setContentEdgeInsets:UIEdgeInsetsMake(
+            self.contentEdgeInsets.top,
+            self.contentEdgeInsets.left + widthOffset / 2,
+            self.contentEdgeInsets.bottom,
+            self.contentEdgeInsets.right + widthOffset / 2
+        )];
+
+        // Move the title slightly left, and account for spacing
+        [self setTitleEdgeInsets:UIEdgeInsetsMake(0, -iconPadding, 0, npadding + calculatedImageSize.width)];
+
+        [_iconView.leadingAnchor constraintEqualToAnchor:self.titleLabel.trailingAnchor constant:iconPadding].active = YES;
+
+        [NSLayoutConstraint constraintWithItem:_iconView
+                                     attribute:NSLayoutAttributeCenterY
+                                     relatedBy:NSLayoutRelationEqual
+                                        toItem:self
+                                     attribute:NSLayoutAttributeCenterY
+                                    multiplier:1.0
+                                      constant:0].active = YES;
+
+        CGFloat offset = -(self.contentEdgeInsets.left + self.contentEdgeInsets.right);
+
+        // Title should not exceed button width minus edge insets
+        self.titleWidthConstraint = [self.titleLabel.widthAnchor constraintLessThanOrEqualToAnchor:self.widthAnchor constant:offset];
+        self.titleWidthConstraint.active = YES;
+
+        // Shift title to left slightly to visually center the whole content (title + icon)
+        [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:-(widthOffset / 2)].active = YES;
+
+        // Ensure button height is enough for title + insets
         self.heightConstraint = [self.heightAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.heightAnchor constant:self.contentEdgeInsets.top + self.contentEdgeInsets.bottom];
         self.heightConstraint.active = YES;
     }
@@ -226,7 +276,8 @@ + (UIButton *)rootView:(ACRView *)rootView
     NSString *iconURL = [NSString stringWithCString:action->GetIconUrl(ACTheme(rootView.theme)).c_str() encoding:[NSString defaultCStringEncoding]];
     NSString *key = iconURL;
     UIImage *img = imageViewMap[key];
-    button.iconPlacement = [ACRButton getIconPlacmentAtCurrentContext:rootView url:key];
+    button.iconPlacement = [ACRButton getIconPlacementAtCurrentContext:rootView url:key];
+    BOOL isSplitButton = action->GetIsSplitAction();
     
     if (img) {
         UIImageView *iconView = [[ACRUIImageView alloc] init];
@@ -250,7 +301,7 @@ + (UIButton *)rootView:(ACRView *)rootView
             UIImageView *view = [[ACRSVGImageView alloc] init:getSVGURL rtl:rootView.context.rtl isFilled:isFilled size:CGSizeMake(imageHeight, imageHeight) tintColor:button.currentTitleColor];
             button.iconView = view;
             [button addSubview:view];
-            [button setImageView:view.image withConfig:config widthToHeightRatio:1.0f];
+            [button setImageView:view.image withConfig:config aspectRatio:1.0f];
         } else if (view) {
             if (view.image) {
                 button.iconView = view;
@@ -268,6 +319,17 @@ + (UIButton *)rootView:(ACRView *)rootView
         button.heightConstraint.active = YES;
     }
     
+    if (isSplitButton)
+    {
+        NSString *chevronDownIcon = @"ChevronDown";
+        NSString *url = [[NSString alloc] initWithFormat:@"%@%@/%@.json", baseFluentIconCDNURL, chevronDownIcon, chevronDownIcon];
+        CGSize iconSize = CGSizeMake(16, 16);
+        UIImageView *view = [[ACRSVGImageView alloc] init:url rtl:rootView.context.rtl isFilled:true size:iconSize tintColor:button.currentTitleColor];
+        view.translatesAutoresizingMaskIntoConstraints = NO;
+        [button addSubview:view];
+        [button setTrailingIcon:view WithConfig:config];
+    }
+    
     if (button.isEnabled == NO) {
         [button setBackgroundColor:[button.backgroundColor colorWithAlphaComponent:0.5]];
     }
@@ -308,7 +370,7 @@ - (BOOL)doesItHaveAnImageView
     return (self.actionType == ACRShowCard && self.imageView && self.imageView.frame.size.width);
 }
 
-+ (ACRIconPlacement)getIconPlacmentAtCurrentContext:(ACRView *)rootView url:(NSString *)key
++ (ACRIconPlacement)getIconPlacementAtCurrentContext:(ACRView *)rootView url:(NSString *)key
 {
     if (!key or key.length == 0) {
         return ACRNoTitle;
@@ -321,4 +383,49 @@ + (ACRIconPlacement)getIconPlacmentAtCurrentContext:(ACRView *)rootView url:(NSS
     return ACRLeftOfTitle;
 }
 
+- (void)setTrailingIcon:(UIImageView *)imageView WithConfig:(ACOHostConfig *)config
+{
+    self.trailingIconView = imageView;
+    int npadding = 0;
+    int iconPadding = [config getHostConfig]->GetSpacing().defaultSpacing;
+    if (self.doesItHaveAnImageView) {
+        iconPadding += (self.imageView.frame.size.width + iconPadding);
+        npadding = [config getHostConfig]->GetSpacing().defaultSpacing;
+    }
+
+    CGFloat rightIconWidth = imageView.image.size.width;
+    CGFloat rightOffset = rightIconWidth + iconPadding;
+
+    [self setContentEdgeInsets:UIEdgeInsetsMake(
+        self.contentEdgeInsets.top,
+        self.contentEdgeInsets.left + rightOffset / 2,
+        self.contentEdgeInsets.bottom,
+        self.contentEdgeInsets.right + rightOffset / 2
+    )];
+
+    // Shift title left to make space for the right icon
+    [self setTitleEdgeInsets:UIEdgeInsetsMake(0, -iconPadding, 0, npadding + rightIconWidth)];
+
+    [imageView.leadingAnchor constraintEqualToAnchor:self.titleLabel.trailingAnchor constant:iconPadding].active = YES;
+
+    [NSLayoutConstraint constraintWithItem:imageView
+                                 attribute:NSLayoutAttributeCenterY
+                                 relatedBy:NSLayoutRelationEqual
+                                    toItem:self
+                                 attribute:NSLayoutAttributeCenterY
+                                multiplier:1.0
+                                  constant:0].active = YES;
+
+    CGFloat offset = -(self.contentEdgeInsets.left + self.contentEdgeInsets.right);
+
+    self.titleWidthConstraint = [self.titleLabel.widthAnchor constraintLessThanOrEqualToAnchor:self.widthAnchor constant:offset];
+    self.titleWidthConstraint.active = YES;
+
+    // Move title slightly left to balance the icon on the right
+    [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:-(rightOffset / 2)].active = YES;
+
+    self.heightConstraint = [self.heightAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.heightAnchor constant:self.contentEdgeInsets.top + self.contentEdgeInsets.bottom];
+    self.heightConstraint.active = YES;
+}
+
 @end
diff --git a/source/shared/cpp/ObjectModel/BaseActionElement.cpp b/source/shared/cpp/ObjectModel/BaseActionElement.cpp
index d98b9d3c2..ff6bf0aab 100644
--- a/source/shared/cpp/ObjectModel/BaseActionElement.cpp
+++ b/source/shared/cpp/ObjectModel/BaseActionElement.cpp
@@ -119,6 +119,16 @@ void AdaptiveCards::BaseActionElement::SetIsEnabled(const bool isEnabled)
     m_isEnabled = isEnabled;
 }
 
+bool BaseActionElement::GetIsRtl() const
+{
+    return m_isRtl;
+}
+
+void AdaptiveCards::BaseActionElement::SetIsRtl(const bool isRtl)
+{
+    m_isRtl = isRtl;
+}
+
 ActionType BaseActionElement::GetElementType() const
 {
     return m_type;
@@ -242,6 +252,7 @@ void BaseActionElement::DeserializeBaseProperties(ParseContext& context, const J
     element->SetTooltip(ParseUtil::GetString(json, AdaptiveCardSchemaKey::Tooltip));
     element->SetIsEnabled(ParseUtil::GetBool(json, AdaptiveCardSchemaKey::IsEnabled, true));
     element->SetRole(ParseUtil::GetEnumValue<ActionRole>(json, AdaptiveCardSchemaKey::ActionRole, ActionRole::Button, ActionRoleFromString));
+    element->SetIsRtl(ParseUtil::GetBool(json, AdaptiveCardSchemaKey::Rtl, false));
 
     auto themedUrls = ParseUtil::GetElementCollectionOfSingleType<ThemedUrl>(context, json, AdaptiveCardSchemaKey::ThemedIconUrls, ThemedUrl::Deserialize, false);
     element->m_themedIconUrls = std::move(themedUrls);
diff --git a/source/shared/cpp/ObjectModel/BaseActionElement.h b/source/shared/cpp/ObjectModel/BaseActionElement.h
index 5913222ed..ad41e8b6a 100644
--- a/source/shared/cpp/ObjectModel/BaseActionElement.h
+++ b/source/shared/cpp/ObjectModel/BaseActionElement.h
@@ -55,6 +55,9 @@ class BaseActionElement : public BaseElement
 
     bool GetIsEnabled() const;
     void SetIsEnabled(const bool isEnabled);
+    
+    bool GetIsRtl() const;
+    void SetIsRtl(const bool isRtl);
 
     ActionRole GetRole() const;
     void SetRole(const ActionRole role);
@@ -109,6 +112,7 @@ class BaseActionElement : public BaseElement
     std::string m_tooltip;
 
     bool m_isEnabled;
+    bool m_isRtl;
 
     ActionType m_type;
     Mode m_mode;


Reviews:
user: login: gauravkeshre
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-28T15:04:39Z
user: login: gauravkeshre
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-28T15:08:33Z
user: login: gauravkeshre
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-28T15:13:29Z
user: login: gauravkeshre
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-28T15:17:06Z
user: login: gauravkeshre
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-28T15:17:37Z
user: login: gauravkeshre
body: Approving with suggestions.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-28T15:18:05Z
user: login: gauravkeshre
body: Approving with suggestions. 
Please also add screenshot to demonstrate RTL language.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-28T15:19:24Z
user: login: meethjain
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-29T08:18:20Z
user: login: gauravkeshre
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-30T08:17:41Z

Review comments:
diff_hunk: @@ -106,6 +106,14 @@ - (void)setImageView:(UIImage *)image
 - (void)setImageView:(UIImage *)image
           withConfig:(ACOHostConfig *)config
   widthToHeightRatio:(float)widthToHeightRatio
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: nit: `widthToHeightRatio` should be called `aspectRatio`
created_at: 2025-04-24T19:21:32Z
author_association: MEMBER
diff_hunk: @@ -106,6 +106,14 @@ - (void)setImageView:(UIImage *)image
 - (void)setImageView:(UIImage *)image
           withConfig:(ACOHostConfig *)config
   widthToHeightRatio:(float)widthToHeightRatio
+{
+    [self setImageView:image withConfig:config widthToHeightRatio:widthToHeightRatio imageSize:CGSizeZero];
+}
+
+- (void)setImageView:(UIImage *)image
+          withConfig:(ACOHostConfig *)config
+  widthToHeightRatio:(float)widthToHeightRatio
+           imageSize:(CGSize)imgSize
 {
     float imageHeight = 0.0f;
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: Can we CGFloat here?
created_at: 2025-04-24T19:26:03Z
author_association: MEMBER
diff_hunk: @@ -121,7 +129,7 @@ - (void)setImageView:(UIImage *)image
         widthToHeightRatio = image.size.width / image.size.height;
     }
     
-    CGSize imageSize = CGSizeMake(imageHeight * widthToHeightRatio, imageHeight);
+    CGSize imageSize = CGSizeEqualToSize(imgSize, CGSizeZero) ? CGSizeMake(imageHeight * widthToHeightRatio, imageHeight) : imgSize;
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: Let's rename these variables to project the distinction. The parameter size can be called `imageSize`
and this local var can be named something like `calculatedSize`
created_at: 2025-04-24T19:35:30Z
author_association: MEMBER
diff_hunk: @@ -121,7 +129,7 @@ - (void)setImageView:(UIImage *)image
         widthToHeightRatio = image.size.width / image.size.height;
     }
     
-    CGSize imageSize = CGSizeMake(imageHeight * widthToHeightRatio, imageHeight);
+    CGSize imageSize = CGSizeEqualToSize(imgSize, CGSizeZero) ? CGSizeMake(imageHeight * widthToHeightRatio, imageHeight) : imgSize;
     _iconView.translatesAutoresizingMaskIntoConstraints = NO;
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: can we not use `iconView` instead of ivar?
created_at: 2025-04-24T19:35:59Z
author_association: MEMBER
diff_hunk: @@ -188,6 +196,48 @@ - (void)setImageView:(UIImage *)image
         
         [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:(widthOffset / 2)].active = YES;
         
+        self.heightConstraint = [self.heightAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.heightAnchor constant:self.contentEdgeInsets.top + self.contentEdgeInsets.bottom];
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: `self.contentEdgeInsets.top + self.contentEdgeInsets.bottom` does not reflect the height of self.
Is this intended? If we need to consider the button height as well we need to add that in constant:
created_at: 2025-04-24T19:42:30Z
author_association: MEMBER
diff_hunk: @@ -188,6 +196,48 @@ - (void)setImageView:(UIImage *)image
         
         [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:(widthOffset / 2)].active = YES;
         
+        self.heightConstraint = [self.heightAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.heightAnchor constant:self.contentEdgeInsets.top + self.contentEdgeInsets.bottom];
+        self.heightConstraint.active = YES;
+    } else if (_iconPlacement == ACRRightOfTitle) {
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: Q: Why Ivar above property?
created_at: 2025-04-24T19:43:12Z
author_association: MEMBER
diff_hunk: @@ -188,6 +196,48 @@ - (void)setImageView:(UIImage *)image
         
         [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:(widthOffset / 2)].active = YES;
         
+        self.heightConstraint = [self.heightAnchor constraintGreaterThanOrEqualToAnchor:self.titleLabel.heightAnchor constant:self.contentEdgeInsets.top + self.contentEdgeInsets.bottom];
+        self.heightConstraint.active = YES;
+    } else if (_iconPlacement == ACRRightOfTitle) {
+        int npadding = 0;
+        if (self.doesItHaveAnImageView) {
+            iconPadding += (self.imageView.frame.size.width + iconPadding);
+            npadding = [config getHostConfig]->GetSpacing().defaultSpacing;
+        }
+
+        CGFloat widthOffset = (imageSize.width + iconPadding);
+
+        // Adjust content insets to accommodate icon on the right
+        [self setContentEdgeInsets:UIEdgeInsetsMake(
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACRButton.mm
user: login: gauravkeshre
body: Did you consider using UIStackView ? 
created_at: 2025-04-24T19:45:13Z
author_association: MEMBER
diff_hunk: @@ -28,6 +28,7 @@
 - (NSData *)additionalProperty;
 - (BOOL)isEnabled;
 - (BOOL)meetsRequirements:(ACOFeatureRegistration *)featureReg;
+- (BOOL)shouldFlipInRtl;
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.h
user: login: gauravkeshre
body: nit: if you make it a readonly computed property the consumer can use the `.` syntax to access this flag.
created_at: 2025-04-28T15:08:33Z
author_association: MEMBER
diff_hunk: @@ -28,6 +28,7 @@
 - (NSData *)additionalProperty;
 - (BOOL)isEnabled;
 - (BOOL)meetsRequirements:(ACOFeatureRegistration *)featureReg;
+- (BOOL)shouldFlipInRtl;
path: source/ios/AdaptiveCards/AdaptiveCards/AdaptiveCards/ACOBaseActionElement.h
user: login: gauravkeshre
body: The `.m` implementation will remain same.
created_at: 2025-04-28T15:13:29Z
author_association: MEMBER
diff_hunk: @@ -119,6 +119,16 @@ void AdaptiveCards::BaseActionElement::SetIsEnabled(const bool isEnabled)
     m_isEnabled = isEnabled;
 }
 
+bool BaseActionElement::GetIsRtl() const
+{
+    return m_isRtl;
+}
+
+void AdaptiveCards::BaseActionElement::SetIsRtl(const bool isRtl)
+{
+    m_isRtl = isRtl;
path: source/shared/cpp/ObjectModel/BaseActionElement.cpp
user: login: gauravkeshre
body: Where is this value being read?
created_at: 2025-04-28T15:17:05Z
author_association: MEMBER
diff_hunk: @@ -119,6 +119,16 @@ void AdaptiveCards::BaseActionElement::SetIsEnabled(const bool isEnabled)
     m_isEnabled = isEnabled;
 }
 
+bool BaseActionElement::GetIsRtl() const
+{
+    return m_isRtl;
+}
+
+void AdaptiveCards::BaseActionElement::SetIsRtl(const bool isRtl)
+{
+    m_isRtl = isRtl;
path: source/shared/cpp/ObjectModel/BaseActionElement.cpp
user: login: gauravkeshre
body: Could you please post the screenshot for RTL language.
created_at: 2025-04-28T15:17:37Z
author_association: MEMBER

PR comments:
user: login: gauravkeshre
created_at: 2025-04-24T19:38:23Z
body: ![Screenshot 2025-04-25 at 1 07 26 AM](https://github.com/user-attachments/assets/1c3b991b-a795-42a0-8ec3-b88afefcd418)
Is this expected?
author_association: MEMBER
user: login: P-Harika
created_at: 2025-04-25T06:30:15Z
body: > ![Screenshot 2025-04-25 at 1 07 26 AM](https://private-user-images.githubusercontent.com/1673315/437178972-1c3b991b-a795-42a0-8ec3-b88afefcd418.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDU1NjI4MjQsIm5iZiI6MTc0NTU2MjUyNCwicGF0aCI6Ii8xNjczMzE1LzQzNzE3ODk3Mi0xYzNiOTkxYi1hNzk1LTQyYTAtOGVjMy1iODhhZmVmY2Q0MTgucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDQyNSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA0MjVUMDYyODQ0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTM2OWFkMTMwMWVmYWI4NjFjYzI0NzQ0M2UxMDgxNmEyMjg1OTk3N2EzNzVkYzgyMGUzNzBlYTRlMWJlZjVkYyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.JFBGSLQwxooZ-6i1_Pe9GhMeMd4DuScxk3h6zpNmigU) Is this expected?

No, but this is present from quite sometime and Teams must be currently overriding this behaviour to display the chevron up icon at right place.
author_association: COLLABORATOR