@swiftbrowser/swift 0.5.3 → 0.5.4

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.
@@ -11,6 +11,9 @@ struct _Element {
11
11
  /// `accessibilityLabel` / `accessibilityIdentifier`, for event scripts (the
12
12
  /// label is in `props` too, Runtime.swift).
13
13
  var accessibility: _AccessibilityMark?
14
+ /// The `accessibilityLabel` prop was taken from the content (a control
15
+ /// named by its icon-only label): a label set on the control replaces it.
16
+ var labelFromContent = false
14
17
  /// `.layoutValue(key:value:)` above this element, by key type: what a
15
18
  /// custom layout's subview reads (CustomLayout.swift).
16
19
  var layoutValues: [ObjectIdentifier: Any]?
@@ -1676,6 +1676,17 @@ public final class _Runtime {
1676
1676
  children: children,
1677
1677
  handler: node.handler ?? hostView._handler
1678
1678
  )
1679
+ // A control whose content shows no text (an icon-only `Label`) is
1680
+ // named by the label its content carries, on the control itself:
1681
+ // browsers and screen readers do not all take a name from an
1682
+ // inner element (a menu's content is its label, the first child).
1683
+ if kind == "button" || kind == "navlink" || kind == "menu", case .object(var fields) = element.props,
1684
+ fields["accessibilityLabel"] == nil,
1685
+ let label = _contentLabel(of: kind == "menu" ? Array(children.prefix(1)) : children) {
1686
+ fields["accessibilityLabel"] = .string(label)
1687
+ element.props = .object(fields)
1688
+ element.labelFromContent = true
1689
+ }
1679
1690
  if traits.contains(.navigationValueLink), let link = node.view as? any _NavigationValueLinkView, let value = link._value {
1680
1691
  element.row = _RowMark(linkValue: value, linkHandler: element.handler)
1681
1692
  }
@@ -1727,9 +1738,11 @@ public final class _Runtime {
1727
1738
  // it already. The innermost label wins; a changed element is a
1728
1739
  // new value, so the reconciler does not skip it as cached.
1729
1740
  if let label = mark.label, !label.isEmpty, case .object(var props) = produced[index].props,
1730
- props["accessibilityLabel"] == nil, !_showsText(label, in: produced[index]) {
1741
+ props["accessibilityLabel"] == nil || produced[index].labelFromContent,
1742
+ !_showsText(label, in: produced[index]) {
1731
1743
  props["accessibilityLabel"] = .string(label)
1732
1744
  produced[index].props = .object(props)
1745
+ produced[index].labelFromContent = false
1733
1746
  produced[index].token = _Element.nextToken()
1734
1747
  }
1735
1748
  }
@@ -1748,6 +1761,22 @@ public final class _Runtime {
1748
1761
  return produced
1749
1762
  }
1750
1763
 
1764
+ /// The accessibility label content carries when it shows no text (the
1765
+ /// first, depth first), else nil.
1766
+ private func _contentLabel(of elements: [_Element]) -> String? {
1767
+ func showsText(_ element: _Element) -> Bool {
1768
+ element.kind == "text" || element.children.contains(where: showsText)
1769
+ }
1770
+ func label(_ element: _Element) -> String? {
1771
+ if case .object(let props) = element.props, case .string(let label)? = props["accessibilityLabel"], !label.isEmpty {
1772
+ return label
1773
+ }
1774
+ return element.children.lazy.compactMap(label).first
1775
+ }
1776
+ guard !elements.contains(where: showsText) else { return nil }
1777
+ return elements.lazy.compactMap(label).first
1778
+ }
1779
+
1751
1780
  /// Whether `element` or an element under it is a `text` showing `text`.
1752
1781
  private func _showsText(_ text: String, in element: _Element) -> Bool {
1753
1782
  if element.kind == "text", case .object(let props) = element.props, case .string(let shown)? = props["text"], shown == text {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swiftbrowser/swift",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "The SwiftBrowser Swift package (the SwiftUI shim, Charts, SwiftData and FoundationBridge) as an npm package, so @swiftbrowser/cli builds apps against the exact version it ships with.",
5
5
  "repository": {
6
6
  "type": "git",