Repository navigation
fix(php-transformer): keep wrapped peer menu items flat and off panel classes - #2743
Merged
Merged
Conversation
… classes A list-less menu that wraps each item (`nav > div.panel > div.content > div.item > a`, as Squarespace's phone menu folders do) was misread twice: - Each item wrapper after the first was taken for the first item's anchor-only submenu cluster, so the panel became one submenu holding every other link. That reading now needs the parent's anchor to be the wrapper's own direct child, which is the documented `<div><a>Parent</a><div><a>Child</a></div></div>` shape. - The shared wrapper class carry walked past the item into the wrappers that hold every item, so the panel's classes (and its off-canvas transform) landed on each item. The walk now stops at a wrapper that also holds another item's link, the same way it stops at a list item. Refs #2726 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chubes4
marked this pull request as ready for review
October 13, 2026 22:44
This was referenced Oct 14, 2026
ellenbauer
added a commit
that referenced
this pull request
Oct 14, 2026
…e it Review of #2743 found two submenu shapes that fell through once peer wrappers stopped reading as submenus: - A Squarespace desktop folder titled by a link (`div.item > a.title + div.panel > div.entry > a`). The anchor-only cluster reading accepted only bare links, so the panel's wrapped entries came out as top-level links in the bar and the title lost the item's classes. - A parent link in a label wrapper (`div > span > a + div > a`). The guard wanted the link as the item's direct child, so the menu was dropped. ownsSubmenuCluster() now accepts the item's own link as a direct child or as the only content of a label wrapper of another tag, and a cluster of links that are bare or one per wrapper (isWrappedLinkPanel(), shared with the aria-controls panel reading). A wrapper of the same tag beside the label is still a peer item. The aria-controls submenu label also leaves out screen-reader-only text. Refs #2726 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ellenbauer
added a commit
that referenced
this pull request
Oct 14, 2026
…l as a submenu (#2781) * fix(php-transformer): read a button that controls a sibling link panel as a submenu A menu item made of a labelled button and the sibling panel it names with aria-controls (`div > button[aria-controls=p] + div#p > div > a ...`) had no reading. Squarespace's desktop folders use it. Before #2743 the first child link was taken as the submenu label; after it the child links were flattened into the top row; with generic names the folder was dropped. buttonDropdownItem() now also accepts that shape when every panel entry is a link, bare or in its own wrapper. The button label becomes the submenu label and the panel's links its children. Refs #2726 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(php-transformer): let an item's own link own the link panel beside it Review of #2743 found two submenu shapes that fell through once peer wrappers stopped reading as submenus: - A Squarespace desktop folder titled by a link (`div.item > a.title + div.panel > div.entry > a`). The anchor-only cluster reading accepted only bare links, so the panel's wrapped entries came out as top-level links in the bar and the title lost the item's classes. - A parent link in a label wrapper (`div > span > a + div > a`). The guard wanted the link as the item's direct child, so the menu was dropped. ownsSubmenuCluster() now accepts the item's own link as a direct child or as the only content of a label wrapper of another tag, and a cluster of links that are bare or one per wrapper (isWrappedLinkPanel(), shared with the aria-controls panel reading). A wrapper of the same tag beside the label is still a peer item. The aria-controls submenu label also leaves out screen-reader-only text. Refs #2726 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(php-transformer): keep peer and titled-column wrappers out of the label submenu reading Review of 0fc24a5: a wrapped label of another tag also matched peers and footer columns: - `div.list > span.item > a` beside `div.item > a` items became a submenu of Home holding the rest; - `p.item > a` beside `div.item > a,a` did the same; - footer columns `div.col > h4 > a + div.links > a,a` became closed submenus. A wrapped label now owns the cluster only when the item holds exactly the two of them, the label is not a heading, and they share neither a tag nor a class. The isAnchorOnlyCluster() docblock is back on its method. Refs #2726 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #2726
What was wrong
On St Francis Pet Hospital (Squarespace), the phone menu opened but its items sat off screen (
translateX(330px)), and every link after "Home" was hidden.Squarespace draws its phone menu as sliding panels ("folders") of item wrappers:
Two generic readings in
NavigationPatternbroke it:primaryNavigationAnchor()andcollectSubmenuContainers()treat an anchor-only wrapper that follows an item's own anchor as that item's submenu (<div><a>Parent</a><div><a>Child</a></div></div>, from bc29d45). They also applied it when the first anchor came from a sibling wrapper of the same shape. So everydiv.header-menu-nav-itemafter "Home" became a child of "Home", and the whole root folder became one closedcore/navigation-submenu.sharedReplacedWrapperClassNames()carries the classes of the wrappers core collapses between an item and its link. Without anliits walk did not stop at the item, so it also took the folder, folder content and wrapper classes, which hold every item. Each item then matched.header-menu-nav-folder{position:absolute;transform:translateX(100%)}. The--activestate class that cancels it on the root folder is not shared by every item, so it was dropped.Either one alone still leaves the items off screen, so both are in this PR, as two scoped changes.
What changed
replacedAncestorWrapperClassNames()stops at a wrapper that also holds another labelled link, the same way it already stops at anli. The per-item wrapper (div.header-menu-nav-item) still carries its classes.Tests
tests/unit/navigation-peer-item-wrappers.php, 3 assertions: wrapped peers stay flat links, panel classes stay off the items, and the per-item wrapper class is still carried. All 3 fail on trunk and pass here.navigation-anchor-cluster-submenu.php(the bc29d45 shapes) still passes.End to end
Studio imports of the St Francis capture with v0.38.1 (the last base that reads these captures), iPhone user agent at 375, dialog opened through its bound trigger. Quality gate passed on both.
translateX(330px), every link after Home inside a closed submenu).composer test(memory_limit -1) passed.Still open (not in this PR)
a[data-folder-id="/aboutus"]opens. Mapping that panel to a submenu needs thedata-folder-idtodata-folderlink, which is Squarespace vocabulary, so it is left for a separate change.🤖 Generated with Claude Code