@craft-native/ios 0.0.481 → 0.0.482

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craft-native/ios",
3
- "version": "0.0.481",
3
+ "version": "0.0.482",
4
4
  "homepage": "https://github.com/craft-native/craft/tree/main/packages/ios#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -3155,6 +3155,44 @@ private class CraftNativeFlowView: UIStackView {
3155
3155
 
3156
3156
  // MARK: Touches
3157
3157
 
3158
+ /// UIKit skips empty component wrappers, including their visible floating
3159
+ /// controls. Supply the real accessible descendants only when such wrappers
3160
+ /// occur; ordinary native subtrees keep UIKit's automatic traversal.
3161
+ private var authoredAccessibilityElements: [Any]?
3162
+ private weak var explicitAccessibilityOwner: CraftNativeFlowView?
3163
+ private var needsExplicitAccessibility: Bool {
3164
+ if let owner = explicitAccessibilityOwner, isDescendant(of: owner), owner.needsExplicitAccessibility { return true }
3165
+ return subviews.contains(where: { $0 is CraftNativeFlowView && $0.bounds.isEmpty })
3166
+ }
3167
+ override var accessibilityElements: [Any]? {
3168
+ get {
3169
+ if let authored = authoredAccessibilityElements { return authored }
3170
+ guard !isAccessibilityElement, needsExplicitAccessibility else { return nil }
3171
+ return subviews.flatMap { Self.accessibleDescendants($0, owner: self) }
3172
+ }
3173
+ set {
3174
+ authoredAccessibilityElements = newValue
3175
+ super.accessibilityElements = newValue
3176
+ }
3177
+ }
3178
+
3179
+ private static func accessibleDescendants(_ view: UIView, owner: CraftNativeFlowView) -> [Any] {
3180
+ guard !view.isHidden, view.alpha > 0.01, !view.accessibilityElementsHidden else { return [] }
3181
+ guard let flow = view as? CraftNativeFlowView, !flow.isAccessibilityElement,
3182
+ flow.accessibilityContainerType == .none else { return [view] }
3183
+ guard !flow.bounds.isEmpty || !flow.clipsToBounds else { return [] }
3184
+ if let authored = flow.authoredAccessibilityElements { return authored }
3185
+ if !flow.bounds.isEmpty {
3186
+ // Keep the real container's identity and frame, and let UIKit
3187
+ // traverse its real children through the same explicit contract.
3188
+ // Flattening every nonempty View discarded ordinary containers
3189
+ // such as the native navigation fixture's max-content bubble.
3190
+ flow.explicitAccessibilityOwner = owner
3191
+ return [flow]
3192
+ }
3193
+ return flow.subviews.flatMap { accessibleDescendants($0, owner: owner) }
3194
+ }
3195
+
3158
3196
  /// A child drawn outside this view's bounds still takes its touches, as an
3159
3197
  /// overflowing element is clickable on the web, unless the view clips
3160
3198
  /// (`overflow: hidden`). UIKit only asks a view's children when the point
@@ -4414,6 +4452,9 @@ private final class CraftNativeSegmentedControl: UISegmentedControl {
4414
4452
  if segments.count != items.count { segments = items.indices.map { CraftNativeSegmentElement(control: self, index: $0) } }
4415
4453
  for (index, item) in items.enumerated() {
4416
4454
  segments[index].accessibilityLabel = item["spoken"] as? String ?? item["label"] as? String ?? values[index]
4455
+ // Match the shared component's <group testID>-<value> identity.
4456
+ // UIKit's private segment views do not inherit identifiers.
4457
+ segments[index].accessibilityIdentifier = accessibilityIdentifier.map { "\($0)-\(values[index])" }
4417
4458
  }
4418
4459
  refreshAccessibilityState()
4419
4460
  setNeedsLayout()